3127780771defc10316dfb2d9b24ae17793ac6df
[platform/core/connectivity/asp-manager.git] / src / tech / asp-tech-infra.c
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 /*****************************************************************************
18  * Standard headers
19  *****************************************************************************/
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <time.h>
25
26 /*****************************************************************************
27  * System headers
28  *****************************************************************************/
29
30 #include <glib.h>
31 #include <dlog.h>
32
33 #include <vconf.h>
34 #include <vconf-keys.h>
35
36 #include <dns-sd.h>
37 #include <dns-sd-internal.h>
38
39 #include <wifi.h>
40
41 /*****************************************************************************
42  * Application Service Platform Daemon headers
43  *****************************************************************************/
44 #include "asp-manager-util.h"
45 #include "asp-service.h"
46 #include "asp-session.h"
47 #include "asp-tech.h"
48 #include "asp-tech-infra.h"
49
50 /*****************************************************************************
51  * Macros and Typedefs
52  *****************************************************************************/
53
54 /* TODO : define service data structure */
55
56 /*****************************************************************************
57  * Global Variables
58  *****************************************************************************/
59 static __thread GHashTable *g_local_service_hash = NULL;
60 static __thread GHashTable *g_browser_hash = NULL;
61
62
63 /* TODO : define local memory for service data structure */
64
65 /*****************************************************************************
66  * Local Functions Definition
67  *****************************************************************************/
68 static void _advertise_status_cb(dnssd_error_e result,
69                 dnssd_service_h local_service, gpointer user_data)
70 {
71         guint32 adv_id = GPOINTER_TO_UINT(user_data);
72         asp_service_advertise_status_e status = 0;
73         asp_service_advertise_reason_e reason = 0;
74
75         switch (result) {
76         case DNSSD_ERROR_NONE:
77         case DNSSD_ERROR_ALREADY_REGISTERED:
78                 status = ASP_SERVICE_ADV_STATUS_ADVERTISED;
79                 reason = ASP_SERVICE_ADVERTISE_REASON_SUCCESS;
80                 break;
81         case DNSSD_ERROR_NAME_CONFLICT:
82                 status = ASP_SERVICE_ADV_STATUS_NOT_ADVERTISED;
83                 reason = ASP_SERVICE_ADVERTISE_REASON_DUP;
84                 break;
85         default:
86                 status = ASP_SERVICE_ADV_STATUS_NOT_ADVERTISED;
87                 reason = ASP_SERVICE_ADVERTISE_REASON_OTHER;
88         }
89
90         asp_service_notify_advertise_status(adv_id, status, reason);
91 }
92
93 static void __txt_record_to_g_hash(unsigned short txt_len, const gchar *txt_records,
94                 GHashTable *service_info_map)
95 {
96         const gchar *ptr = txt_records;
97         const gchar *max = txt_records + txt_len;
98
99         ASP_LOGD("Parsing TXT record. Length: %hu", txt_len);
100
101         while (ptr < max) {
102                 unsigned short len = ptr[0];
103                 gchar *buf = g_strndup(ptr + 1, len);
104                 ASP_LOGD("buf: %s", buf);
105                 gchar *key;
106                 gchar *value;
107                 gchar *save_str = NULL;
108                 key = strtok_r(buf, "=", &save_str);
109                 value = strtok_r(NULL, "=", &save_str);
110                 g_hash_table_replace(service_info_map, g_strdup(key), g_strdup(value));
111                 ASP_LOGD("Insert (%s, %s) to hash. len: %d)", key, value, len);
112                 g_free(buf);
113                 ptr = ptr + 1 + len;
114         }
115 }
116
117 static asp_service_status_e __get_service_status(dnssd_service_state_e service_state)
118 {
119         asp_service_status_e service_status;
120         switch (service_state) {
121         case DNSSD_SERVICE_STATE_AVAILABLE:
122                 service_status = ASP_SERVICE_STATUS_AVAILABLE;
123                 break;
124         case DNSSD_SERVICE_STATE_UNAVAILABLE:
125         case DNSSD_SERVICE_STATE_NAME_LOOKUP_FAILED:
126         case DNSSD_SERVICE_STATE_HOST_NAME_LOOKUP_FAILED:
127         case DNSSD_SERVICE_STATE_ADDRESS_LOOKUP_FAILED:
128                 service_status = ASP_SERVICE_STATUS_NOT_AVAILABLE;
129                 break;
130         default:
131                 service_status = ASP_SERVICE_STATUS_NOT_AVAILABLE;
132         }
133
134         return service_status;
135 }
136
137 static void _search_result_cb(dnssd_service_state_e service_state,
138                 dnssd_service_h remote_service, gpointer user_data)
139 {
140         asp_event_data event;
141         guint32 search_id = -1;
142         gchar *service_mac = NULL;
143         const gchar *service_device_name = NULL;
144         guint32 adv_id = -1;
145         gchar *service_name = NULL;
146         GHashTable *service_info_map = NULL;
147         asp_service_status_e service_status;
148         unsigned short txt_len = 0;
149         gchar *txt = NULL;
150         const gchar *adv_id_str = NULL;
151
152         ASP_LOGD("A service is found %u", remote_service);
153
154         search_id = GPOINTER_TO_UINT(user_data);
155         dnssd_service_get_name(remote_service, &service_name);
156         ASP_LOGD("Service name: %s", service_name);
157
158         service_status = __get_service_status(service_state);
159         ASP_LOGD("Service status: %s",
160                         service_status == ASP_SERVICE_STATUS_AVAILABLE ? "Available" : "Unavailable");
161
162         dnssd_service_get_all_txt_record(remote_service, &txt_len, (gpointer)&txt);
163         if (txt_len > 1) {
164                 service_info_map = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
165                 __txt_record_to_g_hash(txt_len, txt, service_info_map);
166                 if (g_hash_table_contains(service_info_map, ASP_INFRA_ADV_KEY)) {
167                         adv_id_str = g_hash_table_lookup(service_info_map, ASP_INFRA_ADV_KEY);
168                         adv_id = g_ascii_strtoll(adv_id_str, NULL, 10);
169                         ASP_LOGD("Advertisement ID: %u", adv_id);
170                 } else {
171                         ASP_LOGE("TXT records don't contain advertisement ID");
172                         return;
173                 }
174
175                 if (g_hash_table_contains(service_info_map, ASP_INFRA_MAC_ADDR_KEY)) {
176                         service_mac = g_strdup(g_hash_table_lookup(service_info_map, ASP_INFRA_MAC_ADDR_KEY));
177                         ASP_LOGD("Advertisement MAC Address: %s", service_mac);
178                 } else {
179                         ASP_LOGE("TXT records don't contain advertisement MAC");
180                         return;
181                 }
182
183                 if (g_hash_table_contains(service_info_map, ASP_INFRA_DEV_NAME)) {
184                         service_device_name = g_strdup(g_hash_table_lookup(service_info_map, ASP_INFRA_DEV_NAME));
185                         ASP_LOGD("Service device name: %s", service_device_name);
186                 }
187         } else {
188                 ASP_LOGE("Found service should has at least one TXT record");
189                 return;
190         }
191
192         memset(&event, 0x0, sizeof(asp_event_data));
193         event.search_result.tech = ASP_TECH_INFRA;
194         event.search_result.search_id = search_id;
195         event.search_result.advertisement_id = adv_id;
196         event.search_result.service_status = service_status;
197         g_strlcpy(event.search_result.service_mac, service_mac, MACSTR_LEN + 1);
198         event.search_result.device_name = NULL;
199         event.search_result.instance_name = service_name;
200         event.search_result.service_info = service_info_map;
201         asp_manager_event(NULL, ASP_EVENT_SEARCH_RESULT, &event);
202
203         if (service_mac)
204                 g_free(service_mac);
205 }
206
207 static gint32 __asp_service_infra_convert_error_type(gint32 dnssd_error)
208 {
209         switch (dnssd_error) {
210         case DNSSD_ERROR_NONE:
211                 return ASP_ERROR_NONE;
212         case DNSSD_ERROR_OUT_OF_MEMORY:
213                 return ASP_ERROR_MEMORY;
214         case DNSSD_ERROR_INVALID_PARAMETER:
215                 return ASP_ERROR_INVALIED_PARAMS;
216         case DNSSD_ERROR_NOT_SUPPORTED:
217                 return ASP_ERROR_NOT_SUPPORTED_TECH;
218         case DNSSD_ERROR_SERVICE_NOT_FOUND:
219                 return ASP_ERROR_SERVICE_NOT_FOUND;
220         case DNSSD_ERROR_INVALID_OPERATION:
221         case DNSSD_ERROR_NOT_INITIALIZED:
222         case DNSSD_ERROR_ALREADY_REGISTERED:
223         case DNSSD_ERROR_NAME_CONFLICT:
224         case DNSSD_ERROR_SERVICE_NOT_RUNNING:
225         case DNSSD_ERROR_OPERATION_FAILED:
226                 return ASP_ERROR_OPERATION_FAILED;
227         default:
228                 return ASP_ERROR_UNKNOWN;
229         }
230         return dnssd_error;
231 }
232
233 static void __init_hash_tables()
234 {
235         g_local_service_hash = g_hash_table_new(g_int_hash, g_int_equal);
236         g_browser_hash = g_hash_table_new(g_int_hash, g_int_equal);
237 }
238
239 static void __g_hash_free_handle(gpointer key, gpointer value, gpointer user_data)
240 {
241 }
242
243 static void __deinit_hash_tables()
244 {
245         g_hash_table_foreach(g_local_service_hash, (GHFunc)__g_hash_free_handle, NULL);
246         g_hash_table_foreach(g_browser_hash, (GHFunc)__g_hash_free_handle, NULL);
247
248         g_local_service_hash = NULL;
249         g_browser_hash = NULL;
250 }
251
252 static gint32 __add_txt_record(dnssd_service_h handle, const gchar* key, const gchar* value, gint32 len)
253 {
254         gint32 result = 0;
255         unsigned short txt_length;
256         gpointer txt_data;
257
258         result = dnssd_service_add_txt_record(handle, key, (unsigned short)len, value);
259         if (result != DNSSD_ERROR_NONE) {
260                 result = __asp_service_infra_convert_error_type(result);
261                 return result;
262         }
263         ASP_LOGD("Add (%s=%s) TXT record. length: %d", key, value, len);
264
265         result = dnssd_service_get_all_txt_record(handle, &txt_length, &txt_data);
266         if (result != DNSSD_ERROR_NONE) {
267                 result = __asp_service_infra_convert_error_type(result);
268                 return result;
269         }
270         ASP_LOGD("Get all TXT records");
271
272         result = dnssd_service_set_record(handle,
273                         ASP_INFRA_DNSSD_TXT_RECORD_TYPE, txt_length, txt_data);
274         if (result != DNSSD_ERROR_NONE) {
275                 ASP_LOGE("Failed to add record");
276                 result = __asp_service_infra_convert_error_type(result);
277                 return result;
278         }
279         ASP_LOGD("Add TXT records");
280         return result;
281 }
282
283 gint32 asp_tech_infra_init()
284 {
285         __ASP_LOG_FUNC_ENTER__;
286         gint32 result = 0;
287
288         result = dnssd_initialize();
289         if (result != DNSSD_ERROR_NONE) {
290                 result = __asp_service_infra_convert_error_type(result);
291                 return result;
292         }
293
294         __init_hash_tables();
295
296         __ASP_LOG_FUNC_EXIT__;
297         return result;
298 }
299
300 gint32 asp_tech_infra_deinit()
301 {
302         __ASP_LOG_FUNC_ENTER__;
303         gint32 result = 0;
304
305         result = dnssd_deinitialize();
306         if (result != DNSSD_ERROR_NONE) {
307                 result = __asp_service_infra_convert_error_type(result);
308                 return result;
309         }
310
311         __deinit_hash_tables();
312
313         __ASP_LOG_FUNC_EXIT__;
314         return result;
315 }
316
317 gint32 asp_tech_infra_advertise(asp_service_advertise_s *service, gint32 replace)
318 {
319         __ASP_LOG_FUNC_ENTER__;
320         gint32 result = 0;
321         dnssd_service_h service_handle = 0;
322         gchar adv_id[ASP_SERVICE_ADV_ID_LEN + 1];
323         gint32 adv_id_len = 0;
324         gchar *mac_addr;
325         gint32 mac_addr_len;
326         gint32 port = 1234; /* TODO */
327         gchar *if_name;
328
329         ASP_LOGD("Infrastructure advertise service. replace: %d", replace);
330
331         if (replace) {
332                 /*  TODO */
333                 ;
334         }
335
336         result = dnssd_create_local_service(service->service_type, &service_handle);
337         if (result != DNSSD_ERROR_NONE) {
338                 result = __asp_service_infra_convert_error_type(result);
339                 return result;
340         }
341         ASP_LOGD("Success to create local service handle: %u, service type: %s",
342                         service_handle, service->service_type);
343
344         result = dnssd_service_set_name(service_handle, service->instance_name);
345         if (result != DNSSD_ERROR_NONE) {
346                 result = __asp_service_infra_convert_error_type(result);
347                 return result;
348         }
349         ASP_LOGD("Success to set service name %s", service->instance_name);
350
351         /*  TODO set port */
352         result = dnssd_service_set_port(service_handle, port);
353         if (result != DNSSD_ERROR_NONE) {
354                 result = __asp_service_infra_convert_error_type(result);
355                 return result;
356         }
357         ASP_LOGD("Success to set port %d", port);
358
359         result = wifi_initialize();
360         if (result != WIFI_ERROR_NONE) {
361                 ASP_LOGD("Failed to initialize wifi");
362                 return ASP_ERROR_OPERATION_FAILED;
363         }
364         result = wifi_get_network_interface_name(&if_name);
365         if (result != WIFI_ERROR_NONE) {
366                 ASP_LOGD("Failed to get interface name");
367                 return ASP_ERROR_OPERATION_FAILED;
368         }
369         ASP_LOGD("Success to get wifi interface name %s", if_name);
370         result = wifi_deinitialize();
371         if (result != WIFI_ERROR_NONE) {
372                 ASP_LOGD("Failed to deinitialize wifi");
373                 return ASP_ERROR_OPERATION_FAILED;
374         }
375
376         result = dnssd_service_set_interface(service_handle, if_name);
377         if (result != DNSSD_ERROR_NONE) {
378                 result = __asp_service_infra_convert_error_type(result);
379                 return result;
380         }
381         ASP_LOGD("Success to set interface %s", if_name);
382
383         result = dnssd_register_local_service(service_handle,
384                         _advertise_status_cb, GUINT_TO_POINTER(service->adv_id));
385         if (result != DNSSD_ERROR_NONE) {
386                 result = __asp_service_infra_convert_error_type(result);
387                 return result;
388         }
389         ASP_LOGD("Success to register local service %u", service_handle);
390
391         g_hash_table_insert(g_local_service_hash,
392                         &service->adv_id, &service_handle);
393
394         ASP_LOGD("Insert (%u, %u) to g_local_service_hash (size: %d)",
395                         service->adv_id, service_handle,
396                         g_hash_table_size(g_local_service_hash));
397
398
399         /* Add TXT records */
400         /* First of all, add Advertisement ID */
401         snprintf(adv_id, ASP_SERVICE_ADV_ID_LEN + 1, "%u", service->adv_id);
402         adv_id_len = strlen(adv_id);
403         result = __add_txt_record(service_handle, ASP_INFRA_ADV_KEY, adv_id, adv_id_len);
404         if (result != DNSSD_ERROR_NONE) {
405                 result = __asp_service_infra_convert_error_type(result);
406                 return result;
407         }
408
409         /* Add MAC Address to TXT record */
410         mac_addr = vconf_get_str(VCONFKEY_WIFI_BSSID_ADDRESS);
411         mac_addr_len = strlen(mac_addr);
412         result = __add_txt_record(service_handle, ASP_INFRA_MAC_ADDR_KEY, mac_addr, mac_addr_len);
413         if (result != DNSSD_ERROR_NONE) {
414                 result = __asp_service_infra_convert_error_type(result);
415                 g_free(mac_addr);
416                 return result;
417         }
418         g_free(mac_addr);
419
420         /* Other TXT records */
421         if (service->service_info_map != NULL) {
422                 GHashTableIter iter;
423                 gpointer key, value;
424
425                 g_hash_table_iter_init(&iter, service->service_info_map);
426                 while (g_hash_table_iter_next(&iter, &key, &value)) {
427                         unsigned short len = (unsigned short)strlen(value);
428                         result = __add_txt_record(service_handle, key, value, len);
429                 }
430         }
431
432         __ASP_LOG_FUNC_EXIT__;
433         return result;
434 }
435
436 gint32 asp_tech_infra_cancel_advertise(asp_service_advertise_s *service)
437 {
438         __ASP_LOG_FUNC_ENTER__;
439         gint32 result = 0;
440         dnssd_service_h service_handle;
441
442         service_handle = *(dnssd_service_h*)g_hash_table_lookup(g_local_service_hash,
443                                                                                                                 &service->adv_id);
444
445         if (!service_handle) {
446                 /* TODO */
447                 ASP_LOGE("Failed to lookup advertisement id %u", service->adv_id);
448                 return result;
449         }
450
451         result = dnssd_deregister_local_service(service_handle);
452         if (result != DNSSD_ERROR_NONE) {
453                 result = __asp_service_infra_convert_error_type(result);
454                 return result;
455         }
456         ASP_LOGD("Success to deregister local service: %u", service_handle);
457
458         result = dnssd_destroy_local_service(service_handle);
459         if (result != DNSSD_ERROR_NONE) {
460                 result = __asp_service_infra_convert_error_type(result);
461                 return result;
462         }
463         ASP_LOGD("Success to destroy local service: %u", service_handle);
464
465         __ASP_LOG_FUNC_EXIT__;
466         return result;
467 }
468
469 gint32 asp_tech_infra_seek(asp_service_seek_s *service)
470 {
471         __ASP_LOG_FUNC_ENTER__;
472         gint32 result = 0;
473         dnssd_service_h browser_handle;
474         gchar *if_name;
475
476         result = wifi_initialize();
477         if (result != WIFI_ERROR_NONE) {
478                 ASP_LOGD("Failed to initialize wifi");
479                 return ASP_ERROR_OPERATION_FAILED;
480         }
481         result = wifi_get_network_interface_name(&if_name);
482         if (result != WIFI_ERROR_NONE) {
483                 ASP_LOGD("Failed to get interface name");
484                 return ASP_ERROR_OPERATION_FAILED;
485         }
486         ASP_LOGD("Success to get wifi interface name %s", if_name);
487         result = wifi_deinitialize();
488         if (result != WIFI_ERROR_NONE) {
489                 ASP_LOGD("Failed to deinitialize wifi");
490                 return ASP_ERROR_OPERATION_FAILED;
491         }
492
493         result = dnssd_start_browsing_service_on_interface(service->service_type,
494                                                         if_name, &browser_handle,
495                                                         _search_result_cb,
496                                                         GUINT_TO_POINTER(service->search_id));
497
498         if (result != DNSSD_ERROR_NONE) {
499                 result = __asp_service_infra_convert_error_type(result);
500                 return result;
501         }
502         ASP_LOGD("Success to start browsing service. service_type: %s, browser_handle: %u",
503                         service->service_type, browser_handle);
504
505         g_hash_table_insert(g_browser_hash,
506                         &service->search_id, &browser_handle);
507
508         ASP_LOGD("Insert (%u, %u) to g_browser_hash (size: %d)",
509                         service->search_id, browser_handle,
510                         g_hash_table_size(g_browser_hash));
511
512         __ASP_LOG_FUNC_EXIT__;
513         return result;
514 }
515
516 gint32 asp_tech_infra_cancel_seek(asp_service_seek_s *service)
517 {
518         __ASP_LOG_FUNC_ENTER__;
519         gint32 result = 0;
520         dnssd_service_h browser_handle;
521
522         browser_handle = *(dnssd_service_h*)g_hash_table_lookup(g_browser_hash,
523                                                                                                                 &service->search_id);
524
525         if (!browser_handle) {
526                 /* TODO */
527                 ASP_LOGE("Failed to lookup search id %u", service->search_id);
528                 return result;
529         }
530
531         result = dnssd_stop_browsing_service(browser_handle);
532         if (result != DNSSD_ERROR_NONE) {
533                 result = __asp_service_infra_convert_error_type(result);
534                 return result;
535         }
536         ASP_LOGD("Success to stop browsing. browser_handle: %u", browser_handle);
537
538         __ASP_LOG_FUNC_EXIT__;
539         return result;
540 }
541
542 gint32 asp_tech_infra_connect_session(asp_tech_session_request_params_s *params)
543 {
544         __ASP_LOG_FUNC_ENTER__;
545         gint32 result = 0;
546
547         __ASP_LOG_FUNC_EXIT__;
548         return result;
549 }
550
551 gint32 asp_tech_infra_confirm_session(const guint8 *session_mac, gint32 session_id, gint32 confirm, guint32 pin)
552 {
553         __ASP_LOG_FUNC_ENTER__;
554         gint32 result = 0;
555
556         __ASP_LOG_FUNC_EXIT__;
557         return result;
558 }
559
560 gint32 asp_tech_infra_destroy_connection(const guint8 *peer_id, gint32 peer_id_length)
561 {
562         __ASP_LOG_FUNC_ENTER__;
563         gint32 result = 0;
564
565         __ASP_LOG_FUNC_EXIT__;
566         return result;
567 }
568
569 gint32 asp_tech_infra_is_peer_connected(const guint8 *peer_id, gint32 peer_id_length, gint32 *is_connected)
570 {
571         __ASP_LOG_FUNC_ENTER__;
572         gint32 result = 0;
573
574         __ASP_LOG_FUNC_EXIT__;
575         return result;
576 }
577
578 asp_tech_ops_s asp_tech_infra_ops = {
579                 .init = asp_tech_infra_init,
580                 .deinit = asp_tech_infra_deinit,
581                 .advertise = asp_tech_infra_advertise,
582                 .cancel_advertise = asp_tech_infra_cancel_advertise,
583                 .seek = asp_tech_infra_seek,
584                 .cancel_seek = asp_tech_infra_cancel_seek,
585                 .connect_session = asp_tech_infra_connect_session,
586                 .confirm_session = asp_tech_infra_confirm_session,
587                 .destroy_connection = asp_tech_infra_destroy_connection,
588                 .is_peer_connected = asp_tech_infra_is_peer_connected,
589                 .session_request_cb = NULL,
590                 .session_request_cb_user_data = NULL,
591                 .session_config_request_cb = NULL,
592                 .connect_status_cb = NULL,
593                 .connect_status_cb_user_data = NULL,
594                 .ip_assigned_cb = NULL,
595                 .ip_assigned_cb_user_data = NULL,
596 };