2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 /*****************************************************************************
19 *****************************************************************************/
26 /*****************************************************************************
28 *****************************************************************************/
34 #include <vconf-keys.h>
37 #include <dns-sd-internal.h>
41 /*****************************************************************************
42 * Application Service Platform Daemon headers
43 *****************************************************************************/
44 #include "asp-manager-util.h"
45 #include "asp-service.h"
46 #include "asp-session.h"
48 #include "asp-tech-infra.h"
50 /*****************************************************************************
52 *****************************************************************************/
54 /* TODO : define service data structure */
56 /*****************************************************************************
58 *****************************************************************************/
59 static __thread GHashTable *g_local_service_hash = NULL;
60 static __thread GHashTable *g_browser_hash = NULL;
63 /* TODO : define local memory for service data structure */
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)
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;
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;
81 case DNSSD_ERROR_NAME_CONFLICT:
82 status = ASP_SERVICE_ADV_STATUS_NOT_ADVERTISED;
83 reason = ASP_SERVICE_ADVERTISE_REASON_DUP;
86 status = ASP_SERVICE_ADV_STATUS_NOT_ADVERTISED;
87 reason = ASP_SERVICE_ADVERTISE_REASON_OTHER;
90 asp_service_notify_advertise_status(adv_id, status, reason);
93 static void __txt_record_to_g_hash(unsigned short txt_len, const gchar *txt_records,
94 GHashTable *service_info_map)
96 const gchar *ptr = txt_records;
97 const gchar *max = txt_records + txt_len;
99 ASP_LOGD("Parsing TXT record. Length: %hu", txt_len);
102 unsigned short len = ptr[0];
103 gchar *buf = g_strndup(ptr + 1, len);
104 ASP_LOGD("buf: %s", buf);
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);
117 static asp_service_status_e __get_service_status(dnssd_service_state_e service_state)
119 asp_service_status_e service_status;
120 switch (service_state) {
121 case DNSSD_SERVICE_STATE_AVAILABLE:
122 service_status = ASP_SERVICE_STATUS_AVAILABLE;
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;
131 service_status = ASP_SERVICE_STATUS_NOT_AVAILABLE;
134 return service_status;
137 static void _search_result_cb(dnssd_service_state_e service_state,
138 dnssd_service_h remote_service, gpointer user_data)
140 asp_event_data event;
141 guint32 search_id = -1;
142 gchar *service_mac = NULL;
143 const gchar *service_device_name = NULL;
145 gchar *service_name = NULL;
146 GHashTable *service_info_map = NULL;
147 asp_service_status_e service_status;
148 unsigned short txt_len = 0;
150 const gchar *adv_id_str = NULL;
152 ASP_LOGD("A service is found %u", remote_service);
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);
158 service_status = __get_service_status(service_state);
159 ASP_LOGD("Service status: %s",
160 service_status == ASP_SERVICE_STATUS_AVAILABLE ? "Available" : "Unavailable");
162 dnssd_service_get_all_txt_record(remote_service, &txt_len, (gpointer)&txt);
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);
171 ASP_LOGE("TXT records don't contain advertisement ID");
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);
179 ASP_LOGE("TXT records don't contain advertisement MAC");
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);
188 ASP_LOGE("Found service should has at least one TXT record");
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);
207 static gint32 __asp_service_infra_convert_error_type(gint32 dnssd_error)
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;
228 return ASP_ERROR_UNKNOWN;
233 static void __init_hash_tables()
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);
239 static void __g_hash_free_handle(gpointer key, gpointer value, gpointer user_data)
243 static void __deinit_hash_tables()
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);
248 g_local_service_hash = NULL;
249 g_browser_hash = NULL;
252 static gint32 __add_txt_record(dnssd_service_h handle, const gchar* key, const gchar* value, gint32 len)
255 unsigned short txt_length;
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);
263 ASP_LOGD("Add (%s=%s) TXT record. length: %d", key, value, len);
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);
270 ASP_LOGD("Get all TXT records");
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);
279 ASP_LOGD("Add TXT records");
283 gint32 asp_tech_infra_init()
285 __ASP_LOG_FUNC_ENTER__;
288 result = dnssd_initialize();
289 if (result != DNSSD_ERROR_NONE) {
290 result = __asp_service_infra_convert_error_type(result);
294 __init_hash_tables();
296 __ASP_LOG_FUNC_EXIT__;
300 gint32 asp_tech_infra_deinit()
302 __ASP_LOG_FUNC_ENTER__;
305 result = dnssd_deinitialize();
306 if (result != DNSSD_ERROR_NONE) {
307 result = __asp_service_infra_convert_error_type(result);
311 __deinit_hash_tables();
313 __ASP_LOG_FUNC_EXIT__;
317 gint32 asp_tech_infra_advertise(asp_service_advertise_s *service, gint32 replace)
319 __ASP_LOG_FUNC_ENTER__;
321 dnssd_service_h service_handle = 0;
322 gchar adv_id[ASP_SERVICE_ADV_ID_LEN + 1];
323 gint32 adv_id_len = 0;
326 gint32 port = 1234; /* TODO */
329 ASP_LOGD("Infrastructure advertise service. replace: %d", replace);
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);
341 ASP_LOGD("Success to create local service handle: %u, service type: %s",
342 service_handle, service->service_type);
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);
349 ASP_LOGD("Success to set service name %s", service->instance_name);
352 result = dnssd_service_set_port(service_handle, port);
353 if (result != DNSSD_ERROR_NONE) {
354 result = __asp_service_infra_convert_error_type(result);
357 ASP_LOGD("Success to set port %d", port);
359 result = wifi_initialize();
360 if (result != WIFI_ERROR_NONE) {
361 ASP_LOGD("Failed to initialize wifi");
362 return ASP_ERROR_OPERATION_FAILED;
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;
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;
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);
381 ASP_LOGD("Success to set interface %s", if_name);
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);
389 ASP_LOGD("Success to register local service %u", service_handle);
391 g_hash_table_insert(g_local_service_hash,
392 &service->adv_id, &service_handle);
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));
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);
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);
420 /* Other TXT records */
421 if (service->service_info_map != NULL) {
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);
432 __ASP_LOG_FUNC_EXIT__;
436 gint32 asp_tech_infra_cancel_advertise(asp_service_advertise_s *service)
438 __ASP_LOG_FUNC_ENTER__;
440 dnssd_service_h service_handle;
442 service_handle = *(dnssd_service_h*)g_hash_table_lookup(g_local_service_hash,
445 if (!service_handle) {
447 ASP_LOGE("Failed to lookup advertisement id %u", service->adv_id);
451 result = dnssd_deregister_local_service(service_handle);
452 if (result != DNSSD_ERROR_NONE) {
453 result = __asp_service_infra_convert_error_type(result);
456 ASP_LOGD("Success to deregister local service: %u", service_handle);
458 result = dnssd_destroy_local_service(service_handle);
459 if (result != DNSSD_ERROR_NONE) {
460 result = __asp_service_infra_convert_error_type(result);
463 ASP_LOGD("Success to destroy local service: %u", service_handle);
465 __ASP_LOG_FUNC_EXIT__;
469 gint32 asp_tech_infra_seek(asp_service_seek_s *service)
471 __ASP_LOG_FUNC_ENTER__;
473 dnssd_service_h browser_handle;
476 result = wifi_initialize();
477 if (result != WIFI_ERROR_NONE) {
478 ASP_LOGD("Failed to initialize wifi");
479 return ASP_ERROR_OPERATION_FAILED;
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;
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;
493 result = dnssd_start_browsing_service_on_interface(service->service_type,
494 if_name, &browser_handle,
496 GUINT_TO_POINTER(service->search_id));
498 if (result != DNSSD_ERROR_NONE) {
499 result = __asp_service_infra_convert_error_type(result);
502 ASP_LOGD("Success to start browsing service. service_type: %s, browser_handle: %u",
503 service->service_type, browser_handle);
505 g_hash_table_insert(g_browser_hash,
506 &service->search_id, &browser_handle);
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));
512 __ASP_LOG_FUNC_EXIT__;
516 gint32 asp_tech_infra_cancel_seek(asp_service_seek_s *service)
518 __ASP_LOG_FUNC_ENTER__;
520 dnssd_service_h browser_handle;
522 browser_handle = *(dnssd_service_h*)g_hash_table_lookup(g_browser_hash,
523 &service->search_id);
525 if (!browser_handle) {
527 ASP_LOGE("Failed to lookup search id %u", service->search_id);
531 result = dnssd_stop_browsing_service(browser_handle);
532 if (result != DNSSD_ERROR_NONE) {
533 result = __asp_service_infra_convert_error_type(result);
536 ASP_LOGD("Success to stop browsing. browser_handle: %u", browser_handle);
538 __ASP_LOG_FUNC_EXIT__;
542 gint32 asp_tech_infra_connect_session(asp_tech_session_request_params_s *params)
544 __ASP_LOG_FUNC_ENTER__;
547 __ASP_LOG_FUNC_EXIT__;
551 gint32 asp_tech_infra_confirm_session(const guint8 *session_mac, gint32 session_id, gint32 confirm, guint32 pin)
553 __ASP_LOG_FUNC_ENTER__;
556 __ASP_LOG_FUNC_EXIT__;
560 gint32 asp_tech_infra_destroy_connection(const guint8 *peer_id, gint32 peer_id_length)
562 __ASP_LOG_FUNC_ENTER__;
565 __ASP_LOG_FUNC_EXIT__;
569 gint32 asp_tech_infra_is_peer_connected(const guint8 *peer_id, gint32 peer_id_length, gint32 *is_connected)
571 __ASP_LOG_FUNC_ENTER__;
574 __ASP_LOG_FUNC_EXIT__;
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,