From b7cae49a6d1b4c5dba12647e2b30e635b8993a92 Mon Sep 17 00:00:00 2001
From: Raquel Medina <raquel.medina@konsulko.com>
Date: Sun, 25 Nov 2018 02:17:48 +0200
Subject: binding: nfc: Process content data from tag (adapter in tag reader
 mode)

 Bug-AGL: SPEC-1975

   - Register callback for tag found
   - Update callback for record found
   - Fix memory leak

Change-Id: I870648f3c5771aa1b54b710ef6b75786a1c67f65
Signed-off-by: Raquel Medina <raquel.medina@konsulko.com>
---
 binding/afm-nfc-binding.c | 292 ++++++++++++++++++++++++++++++----------------
 1 file changed, 189 insertions(+), 103 deletions(-)

(limited to 'binding')

diff --git a/binding/afm-nfc-binding.c b/binding/afm-nfc-binding.c
index 6fc26d9..1037227 100644
--- a/binding/afm-nfc-binding.c
+++ b/binding/afm-nfc-binding.c
@@ -31,109 +31,190 @@
 #include <neardal/neardal.h>
 #define AFB_BINDING_VERSION 3
 #include <afb/afb-binding.h>
-
 #include "afm-nfc-common.h"
 
+#define STR(X) STR1(X)
+#define STR1(X) #X
+
 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 static afb_event_t presence_event;
 
-static void neard_cb_record_found(const char *tag_name, void *ptr)
+static void __attribute__((unused)) dbg_dump_tag_records(neardal_tag *tag)
 {
-        nfc_binding_data *data = ptr;
-        neardal_record *record;
+	char **recs = tag->records;
+	int i;
 
-        int ret = neardal_get_record_properties(tag_name, &record);
-        if (ret == NEARDAL_SUCCESS) {
-                GVariantIter iter;
-                char *s = NULL;
-                GVariant *v, *value = (neardal_record_to_g_variant(record));
-                json_object *jresp = json_object_new_object();
-                json_object *jdict = json_object_new_object();
+	if (!recs) {
+		AFB_API_DEBUG(afbBindingV3root, "tag empty!");
+		return;
+	}
 
-                g_variant_iter_init(&iter, value);
-                json_object_object_add(jresp, "status",
-                                       json_object_new_string("detected"));
+	for (i = 0; recs[i] != NULL; i++)
+		AFB_API_DEBUG(afbBindingV3root, "tag record[n]: %s", recs[i]);
 
-                while (g_variant_iter_loop(&iter, "{sv}", &s, &v)) {
-                        gchar *str;
+	return;
+}
 
-			if (g_strcmp0("Name", s) == 0)
-				continue;
 
-			str =  g_variant_print(v, 0);
-                        str[strlen(str) - 1] = '\0';
-                        json_object_object_add(jdict, s,
-                                               json_object_new_string(str + 1));
-                        g_free(str);
-                }
+static void __attribute__((unused)) dbg_dump_record_content(neardal_record record)
+{
+#define DBG_RECORD(__x) if (record.__x)  \
+	AFB_API_DEBUG(afbBindingV3root, "record %s=%s", STR(__x), (record.__x))
+
+	DBG_RECORD(authentication);
+	DBG_RECORD(representation);
+	DBG_RECORD(passphrase);
+	DBG_RECORD(encryption);
+	DBG_RECORD(encoding);
+	DBG_RECORD(language);
+	DBG_RECORD(action);
+	DBG_RECORD(mime);
+	DBG_RECORD(type);
+	DBG_RECORD(ssid);
+	DBG_RECORD(uri);
+}
 
- 		json_object_object_add(jresp, "record", jdict);
+static void record_found(const char *tag_name, void *ptr)
+{
+	json_object *jresp, *jdict, *jtemp;
+	nfc_binding_data *data = ptr;
+	neardal_record *record;
+	GVariant *value, *v = NULL;
+	GVariantIter iter;
+	char *s = NULL;
+	int ret;
+
+	ret = neardal_get_record_properties(tag_name, &record);
+	if (ret != NEARDAL_SUCCESS) {
+		AFB_API_ERROR(afbBindingV3root,
+			      "read record properties for %s tag, err:0x%x (%s)",
+			      tag_name, ret, neardal_error_get_text(ret));
+		return;
+	}
 
-		neardal_free_record(record);
+	value = neardal_record_to_g_variant(record);
+	jresp = json_object_new_object();
+	jdict = json_object_new_object();
 
-                pthread_mutex_lock(&mutex);
-                data->jresp = jresp;
-                json_object_get(jresp);
-                pthread_mutex_unlock(&mutex);
+	g_variant_iter_init(&iter, value);
+	json_object_object_add(jresp,
+			       "status", json_object_new_string("detected"));
 
-                afb_event_push(presence_event, jresp);
-        }
+	while (g_variant_iter_loop(&iter, "{sv}", &s, &v)) {
+		gchar *str = g_variant_print(v, 0);
+
+		str[strlen(str) - 1] = '\0';
+		AFB_API_DEBUG(afbBindingV3root,
+			      "%s tag, record %s= %s", tag_name, s, str);
+
+		json_object_object_add(jdict, s,
+                                       json_object_new_string(str + 1));
+		g_free(str);
+	}
+
+	neardal_free_record(record);
+
+	/*
+	 * get record dictionary and look for 'Representation' field which should
+	 * contain the uid value the identity agent needs.
+	 *
+	 */
+	if (json_object_object_get_ex(jdict, "Representation", &jtemp)) {
+		const char *uid = json_object_get_string(jtemp);
+
+		pthread_mutex_lock(&mutex);
+		data->jresp = jresp;
+		json_object_object_add(jresp, "uid", json_object_new_string(uid));
+		pthread_mutex_unlock(&mutex);
+
+		afb_event_push(presence_event, jresp);
+		AFB_API_DEBUG(afbBindingV3root,
+			      "sent presence event, record content %s, tag %s",
+			      uid, tag_name);
+	}
+
+	return;
 }
 
-static void neard_cb_tag_removed(const char *tag_name, void *ptr)
+static void tag_found(const char *tag_name, void *ptr)
 {
-        nfc_binding_data *data = ptr;
-        json_object *jresp = json_object_new_object();
+	neardal_tag *tag;
+	int ret;
 
-        pthread_mutex_lock(&mutex);
-        if (data->jresp) {
-                json_object_put(data->jresp);
-                data->jresp = NULL;
-        }
-        pthread_mutex_unlock(&mutex);
-	
-        json_object_object_add(jresp, "status",
-                               json_object_new_string("removed"));
+	ret = neardal_get_tag_properties(tag_name, &tag);
+	if (ret != NEARDAL_SUCCESS) {
+		AFB_API_ERROR(afbBindingV3root,
+			      "read tag %s properties, err:0x%x (%s)",
+			      tag_name, ret, neardal_error_get_text(ret));
+		return;
+	}
+
+	dbg_dump_tag_records(tag);
+	neardal_free_tag(tag);
+
+	return;
+}
+
+static void tag_removed(const char *tag_name, void *ptr)
+{
+	nfc_binding_data *data = ptr;
+	json_object *jresp;
+
+	pthread_mutex_lock(&mutex);
+	if (data->jresp) {
+		json_object_put(data->jresp);
+		data->jresp = NULL;
+	}
+	pthread_mutex_unlock(&mutex);
 
-        afb_event_push(presence_event, jresp);
+	jresp = json_object_new_object();
+	json_object_object_add(jresp, "status",
+			       json_object_new_string("removed"));
+	afb_event_push(presence_event, jresp);
 
-        g_main_loop_quit(data->loop);
+	AFB_API_DEBUG(afbBindingV3root, "%s tag removed, quit loop", tag_name);
+	g_main_loop_quit(data->loop);
 }
 
 static void *poll_adapter(void *ptr)
 {
-        nfc_binding_data *data = ptr;
-        int ret;
-
-        data->loop = g_main_loop_new(NULL, FALSE);
-
-        neardal_set_cb_tag_lost(neard_cb_tag_removed, ptr);
-        neardal_set_cb_record_found(neard_cb_record_found, ptr);
-
-        ret = neardal_set_adapter_property(data->adapter,
-                                           NEARD_ADP_PROP_POWERED,
-                                           GINT_TO_POINTER(1));
-        if (ret != NEARDAL_SUCCESS) {
-                AFB_API_DEBUG(afbBindingV3root,
-                          "failed to power %s adapter on: ret=0x%x (%s)",
-                          data->adapter, ret, neardal_error_get_text(ret));
-                g_free(data->adapter);
-                return NULL;
-        }
+	nfc_binding_data *data = ptr;
+	int ret;
 
-        while (1) {
-                ret = neardal_start_poll(data->adapter);
+	data->loop = g_main_loop_new(NULL, FALSE);
 
-                if ((ret != NEARDAL_SUCCESS) &&
-                    (ret != NEARDAL_ERROR_POLLING_ALREADY_ACTIVE)) 
-                        break;
+	neardal_set_cb_tag_found(tag_found, ptr);
+	neardal_set_cb_tag_lost(tag_removed, ptr);
+	neardal_set_cb_record_found(record_found, ptr);
 
-                g_main_loop_run(data->loop);
-        }
+	ret = neardal_set_adapter_property(data->adapter,
+					   NEARD_ADP_PROP_POWERED,
+					   GINT_TO_POINTER(1));
+	if (ret != NEARDAL_SUCCESS) {
+		AFB_API_DEBUG(afbBindingV3root,
+			      "failed to power %s adapter on: ret=0x%x (%s)",
+			      data->adapter, ret, neardal_error_get_text(ret));
+
+		goto out;
+	}
+
+	for (;;) {
+		ret = neardal_start_poll(data->adapter);
+
+		if ((ret != NEARDAL_SUCCESS) &&
+		    (ret != NEARDAL_ERROR_POLLING_ALREADY_ACTIVE))
+			break;
+
+		g_main_loop_run(data->loop);
+	}
 
-        g_free(data->adapter);
+	AFB_API_DEBUG(afbBindingV3root, "exiting polling loop");
 
-        return NULL;
+out:
+	g_free(data->adapter);
+	free(data);
+
+	return NULL;
 }
 
 static int get_adapter(nfc_binding_data *data, unsigned int id)
@@ -146,52 +227,59 @@ static int get_adapter(nfc_binding_data *data, unsigned int id)
 		AFB_API_DEBUG(afbBindingV3root,
 			      "failed to find adapters ret=0x%x (%s)",
 			      ret, neardal_error_get_text(ret));
-
 		return -EIO;
 	}
 
 	if (id > num_adapters - 1) {
-		AFB_API_DEBUG(afbBindingV3root, 
-			      "adapter out of range (%d - %d)", 
+		AFB_API_DEBUG(afbBindingV3root,
+			      "adapter out of range (%d - %d)",
 			      id, num_adapters);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
 	data->adapter = g_strdup(adapters[id]);
-	neardal_free_array(&adapters);
 
+out:
+	neardal_free_array(&adapters);
 	return ret;
 }
 
 static int init(afb_api_t api)
 {
-        nfc_binding_data *data;
-        pthread_t thread_id;
-        int ret;
-
-        data = malloc(sizeof(nfc_binding_data));
-        if (data == NULL)
-                return -ENOMEM;
-
-        presence_event = afb_api_make_event(api, "presence");
-        if (!afb_event_is_valid(presence_event)) {
-                AFB_API_ERROR(api, "Failed to create event");
-                return -EINVAL;
-        }
+	nfc_binding_data *data;
+	pthread_t thread_id;
+	int ret;
+
+	data = malloc(sizeof(nfc_binding_data));
+	if (!data)
+		return -ENOMEM;
+
+	presence_event = afb_api_make_event(api, "presence");
+	if (!afb_event_is_valid(presence_event)) {
+		AFB_API_ERROR(api, "Failed to create event");
+		free(data);
+		return -EINVAL;
+	}
 
 	/* get the first adapter */
-        ret = get_adapter(data, 0);
-	if (ret != NEARDAL_SUCCESS)
-		return 0;
+	ret = get_adapter(data, 0);
+	if (ret != NEARDAL_SUCCESS) {
+		free(data);
+		return 0;  /* ignore error if no adapter */
+	}
 
 	AFB_API_DEBUG(api, " %s adapter found", data->adapter);
 
 	afb_api_set_userdata(api, data);
 	ret = pthread_create(&thread_id, NULL, poll_adapter, data);
-	if (ret)
+	if (ret) {
 		AFB_API_ERROR(api, "polling pthread creation failed");
+		g_free(data->adapter);
+		free(data);
+	}
 
-        return 0;
+	return 0;
 }
 
 static void subscribe(afb_req_t request)
@@ -202,15 +290,14 @@ static void subscribe(afb_req_t request)
 
 		return;
         }
-     
+
 	afb_req_reply(request, NULL, NULL, NULL);
 }
 
 static void unsubscribe(afb_req_t request)
 {
         if (afb_req_unsubscribe(request, presence_event) < 0) {
-                AFB_REQ_ERROR(request,
-                              "unsubscribe to presence_event failed");
+                AFB_REQ_ERROR(request, "unsubscribe to presence_event failed");
                 afb_req_reply(request, NULL, "failed", "Invalid event");
 
 		return;
@@ -219,10 +306,10 @@ static void unsubscribe(afb_req_t request)
 	afb_req_reply(request, NULL, NULL, NULL);
 }
 
-const afb_verb_t binding_verbs[] = {
-        { .verb = "subscribe",   .callback = subscribe,
+static const afb_verb_t binding_verbs[] = {
+        { .verb = "subscribe",   .callback = subscribe, 
 	  .info = "Subscribe to NFC events" },
-        { .verb = "unsubscribe", .callback = unsubscribe,
+        { .verb = "unsubscribe", .callback = unsubscribe, 
 	  .info = "Unsubscribe to NFC events" },
         { .verb = NULL }
 };
@@ -240,4 +327,3 @@ const afb_binding_t afbBindingExport = {
         .onevent        = NULL,
         .noconcurrency  = 0
 };
-
-- 
cgit