p2p: Factorize bind and listening routines
authorSamuel Ortiz <sameo@linux.intel.com>
Fri, 3 Feb 2012 00:19:12 +0000 (01:19 +0100)
committerSamuel Ortiz <sameo@linux.intel.com>
Fri, 3 Feb 2012 00:19:12 +0000 (01:19 +0100)
plugins/npp.c
plugins/p2p.c
plugins/p2p.h
plugins/snep.c

index 6c2867b..4178ac4 100644 (file)
 
 #include "p2p.h"
 
-#define NPP_SN "com.android.npp"
-
-struct p2p_npp_channel {
-       near_tag_io_cb cb;
-       uint32_t adapter_idx;
-       uint32_t target_idx;
-       int fd;
-       guint watch;
-       GIOChannel *channel;
-};
-
 struct p2p_npp_ndef_entry {
        uint8_t action;
        uint32_t ndef_length;
@@ -65,24 +54,24 @@ struct p2p_npp_frame {
        struct p2p_npp_ndef_entry ndefs[];
 } __attribute__((packed));
 
-static struct p2p_npp_channel npp_server;
-
-static void npp_read_ndef(int client_fd)
+static int npp_read(int client_fd, uint32_t adapter_idx, uint32_t target_idx,
+               near_tag_io_cb cb)
 {
        struct near_tag *tag;
        struct p2p_npp_frame frame;
        struct p2p_npp_ndef_entry entry;
-       int bytes_recv, n_ndef, i, ndef_length, total_ndef_length;
+       int bytes_recv, n_ndef, i, ndef_length, total_ndef_length, err;
        size_t tag_length;
        uint8_t *ndefs, *nfc_data, *current_ndef;
 
        ndefs = NULL;
        total_ndef_length = 0;
+       err = 0;
 
        bytes_recv = recv(client_fd, &frame, sizeof(frame), 0);
        if (bytes_recv < 0) {
                near_error("Could not read NPP frame %d", bytes_recv);
-               return;
+               return bytes_recv;
        }
 
        n_ndef = GINT_FROM_BE(frame.n_ndef);
@@ -94,6 +83,7 @@ static void npp_read_ndef(int client_fd)
                if (bytes_recv < 0) {
                        near_error("Could not read NPP NDEF entry %d",
                                                                bytes_recv);
+                       err = bytes_recv;
                        break;
                }
 
@@ -105,6 +95,7 @@ static void npp_read_ndef(int client_fd)
                if (ndefs == NULL) {
                        near_error("Could not allocate NDEF buffer %d",
                                                                bytes_recv);
+                       err = -ENOMEM;
                        break;
                }
 
@@ -118,21 +109,21 @@ static void npp_read_ndef(int client_fd)
                if (bytes_recv < 0) {
                        near_error("Could not read NDEF entry %d",
                                                        bytes_recv);
+                       err = bytes_recv;
                        break;
                }
        }
 
        if (total_ndef_length == 0)
-               return;
+               return err;
 
        DBG("Total NDEF length %d", total_ndef_length);
 
-       tag = near_target_add_tag(npp_server.adapter_idx,
-                                       npp_server.target_idx,
+       tag = near_target_add_tag(adapter_idx, target_idx,
                                        total_ndef_length);
        if (tag == NULL) {
                g_free(ndefs);
-               return;
+               return -ENOMEM;
        }
 
        for (i = 0; i < total_ndef_length; i++)
@@ -141,97 +132,25 @@ static void npp_read_ndef(int client_fd)
        nfc_data = near_tag_get_data(tag, &tag_length);
        memcpy(nfc_data, ndefs, total_ndef_length);
 
-       near_tlv_parse(tag, npp_server.cb, nfc_data, total_ndef_length);
+       near_tlv_parse(tag, cb, nfc_data, total_ndef_length);
 
        g_free(ndefs);
-}
-
-static gboolean npp_listener_event(GIOChannel *channel, GIOCondition condition,
-                                                       gpointer user_data)
-{
-       struct sockaddr_nfc_llcp client_addr;
-       int server_fd, client_fd;
-       socklen_t client_addr_len;
-
-       DBG("condition 0x%x", condition);
-
-       if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
-               if (npp_server.watch > 0)
-                       g_source_remove(npp_server.watch);
-               npp_server.watch = 0;
-
-               near_error("Error with NPP server channel");
-
-               return FALSE;
-       }
-
-       if (condition & G_IO_IN) {
-               server_fd = g_io_channel_unix_get_fd(channel);
-
-               client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_addr_len);
-               if (client_fd < 0) {
-                       near_error("accept failed %d", client_fd);
-
-                       close(server_fd);
-                       return FALSE;
-               }
-
-               DBG("client dsap %d ssap %d",
-                       client_addr.dsap, client_addr.ssap);
 
-               npp_read_ndef(client_fd);
-
-               close(client_fd);
+       return 0;
+}
 
-               return FALSE;
-       }
+struct near_p2p_driver npp_driver = {
+       .name = "NPP",
+       .service_name = "com.android.npp",
+       .read = npp_read,
+};
 
-       return FALSE;
+int npp_init(void)
+{
+       return near_p2p_register(&npp_driver);
 }
 
-int npp_bind(uint32_t adapter_idx, uint32_t target_idx,
-                                       near_tag_io_cb cb)
+void npp_exit(void)
 {
-       int err;
-       struct sockaddr_nfc_llcp addr;
-
-       npp_server.adapter_idx = adapter_idx;
-       npp_server.target_idx = target_idx;
-       npp_server.cb = cb;
-       npp_server.fd = socket(AF_NFC, SOCK_STREAM, NFC_SOCKPROTO_LLCP);
-       if (npp_server.fd < 0)
-               return -errno;
-
-       memset(&addr, 0, sizeof(struct sockaddr_nfc_llcp));
-       addr.sa_family = AF_NFC;
-       addr.dev_idx = adapter_idx;
-       addr.nfc_protocol = NFC_PROTO_NFC_DEP;
-       addr.service_name_len = strlen(NPP_SN);
-       strcpy(addr.service_name, NPP_SN);
-
-       err = bind(npp_server.fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_nfc_llcp));
-       if (err < 0) {
-               near_error("NPP bind failed %d", err);
-
-               close(npp_server.fd);
-               return err;
-       }
-
-       err = listen(npp_server.fd, 10);
-       if (err < 0) {
-               near_error("NPP listen failed %d", err);
-
-               close(npp_server.fd);
-               return err;
-       }
-
-       npp_server.channel = g_io_channel_unix_new(npp_server.fd);
-       g_io_channel_set_close_on_unref(npp_server.channel, TRUE);
-
-       npp_server.watch = g_io_add_watch(npp_server.channel,
-                               G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
-                               npp_listener_event,
-                               (gpointer) &npp_server.channel);
-
-       return 0;
+       near_p2p_unregister(&npp_driver);
 }
index 29f482f..d38795d 100644 (file)
 #include <config.h>
 #endif
 
+#include <unistd.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include <linux/socket.h>
+#include <linux/nfc.h>
+
 #include <near/plugin.h>
 #include <near/log.h>
 #include <near/types.h>
-#include <near/tag.h>
+#include <near/target.h>
+#include <near/tlv.h>
 
 #include "p2p.h"
 
-static int p2p_read(uint32_t adapter_idx,
+static GSList *driver_list = NULL;
+
+struct p2p_driver_data {
+       struct near_p2p_driver *driver;
+       uint32_t adapter_idx;
+       uint32_t target_idx;
+       near_tag_io_cb cb;
+       int server_fd;
+       guint watch;
+};
+
+static gboolean p2p_listener_event(GIOChannel *channel, GIOCondition condition,
+                                                       gpointer user_data)
+{
+       struct sockaddr_nfc_llcp client_addr;
+       int server_fd, client_fd;
+       socklen_t client_addr_len;
+       struct p2p_driver_data *driver_data = user_data;
+       struct near_p2p_driver *driver = driver_data->driver;
+
+       DBG("condition 0x%x", condition);
+
+       if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+               if (driver_data->watch > 0)
+                       g_source_remove(driver_data->watch);
+               driver_data->watch = 0;
+
+               near_error("Error with %s server channel", driver->name);
+
+               return FALSE;
+       }
+
+       if (condition & G_IO_IN) {
+               server_fd = g_io_channel_unix_get_fd(channel);
+
+               client_fd = accept(server_fd, (struct sockaddr *)&client_addr,
+                                                       &client_addr_len);
+               if (client_fd < 0) {
+                       near_error("accept failed %d", client_fd);
+
+                       close(server_fd);
+                       return FALSE;
+               }
+
+               DBG("client dsap %d ssap %d",
+                       client_addr.dsap, client_addr.ssap);
+
+               driver->read(client_fd, driver_data->adapter_idx,
+                               driver_data->target_idx, driver_data->cb);
+
+               close(client_fd);
+
+               return FALSE;
+       }
+
+       return FALSE;
+}
+
+static int p2p_bind(struct near_p2p_driver *driver, uint32_t adapter_idx,
                uint32_t target_idx, near_tag_io_cb cb)
 {
-       int err;
+       int err, fd;
+       struct sockaddr_nfc_llcp addr;
+       GIOChannel *channel;
+       struct p2p_driver_data *driver_data;
+
+       DBG("Binding %s", driver->name);
+
+       fd = socket(AF_NFC, SOCK_STREAM, NFC_SOCKPROTO_LLCP);
+       if (fd < 0)
+               return -errno;
+
+       memset(&addr, 0, sizeof(struct sockaddr_nfc_llcp));
+       addr.sa_family = AF_NFC;
+       addr.dev_idx = adapter_idx;
+       addr.nfc_protocol = NFC_PROTO_NFC_DEP;
+       addr.service_name_len = strlen(driver->service_name);
+       strcpy(addr.service_name, driver->service_name);
+
+       err = bind(fd, (struct sockaddr *)&addr,
+                       sizeof(struct sockaddr_nfc_llcp));
+       if (err < 0) {
+               near_error("%s bind failed %d", driver->name, err);
+
+               close(fd);
+               return err;
+       }
+
+       err = listen(fd, 10);
+       if (err < 0) {
+               near_error("%s listen failed %d", driver->name, err);
 
-       err = snep_bind(adapter_idx, target_idx, cb);
-       if (err < 0)
+               close(fd);
                return err;
+       }
+
+       driver_data = g_try_malloc0(sizeof(struct p2p_driver_data));
+       if (driver_data == NULL) {
+               close(fd);
+               return -ENOMEM;
+       }
+
+       driver_data->driver = driver;
+       driver_data->adapter_idx = adapter_idx;
+       driver_data->target_idx = target_idx;
+       driver_data->server_fd = fd;
+       driver_data->cb = cb;
+
+       channel = g_io_channel_unix_new(fd);
+       g_io_channel_set_close_on_unref(channel, TRUE);
+
+       driver_data->watch = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
+                               p2p_listener_event,
+                               (gpointer) driver_data);
+
+       return 0;
+}
+
+static int p2p_read(uint32_t adapter_idx,
+               uint32_t target_idx, near_tag_io_cb cb)
+{
+       int err = 0;
+       GSList *list;
+
+       for (list = driver_list; list != NULL; list = list->next) {
+               struct near_p2p_driver *driver = list->data;
 
-       return npp_bind(adapter_idx, target_idx, cb);
+               err &= p2p_bind(driver, adapter_idx, target_idx, cb);
+       }
+
+       return err;
 }
 
 static struct near_tag_driver p2p_driver = {
@@ -47,10 +179,30 @@ static struct near_tag_driver p2p_driver = {
                .read_tag = p2p_read,
 };
 
+
+int near_p2p_register(struct near_p2p_driver *driver)
+{
+       DBG("driver %p name %s", driver, driver->name);
+
+       driver_list = g_slist_prepend(driver_list, driver);
+
+       return 0;
+}
+
+void near_p2p_unregister(struct near_p2p_driver *driver)
+{
+       DBG("driver %p name %s", driver, driver->name);
+
+       driver_list = g_slist_remove(driver_list, driver);
+}
+
 static int p2p_init(void)
 {
        DBG("");
 
+       npp_init();
+       snep_init();
+
        return near_tag_driver_register(&p2p_driver);
 }
 
@@ -58,6 +210,9 @@ static void p2p_exit(void)
 {
        DBG("");
 
+       snep_exit();
+       npp_exit();
+
        near_tag_driver_unregister(&p2p_driver);
 }
 
index 4637dc0..34e314b 100644 (file)
 #define AF_NFC 39
 #endif
 
+struct near_p2p_driver {
+       const char *name;
+       const char *service_name;
+       int (*read)(int client_fd, uint32_t adapter_idx, uint32_t target_idx,
+               near_tag_io_cb cb);
+};
+
 #define TLV_SIZE 2
 
-int npp_bind(uint32_t adapter_idx, uint32_t target_idx, near_tag_io_cb cb);
-int snep_bind(uint32_t adapter_idx, uint32_t target_idx, near_tag_io_cb cb);
+int npp_init(void);
+void npp_exit(void);
+
+int snep_init(void);
+void snep_exit(void);
+
+int near_p2p_register(struct near_p2p_driver *driver);
+void near_p2p_unregister(struct near_p2p_driver *driver);
index cfc945a..b5b1506 100644 (file)
 #define SNEP_RESP_VERSION   0x80
 #define SNEP_RESP_REJECT    0x80
 
-struct p2p_snep_channel {
-       near_tag_io_cb cb;
-       uint32_t adapter_idx;
-       uint32_t target_idx;
-       int fd;
-       guint watch;
-       GIOChannel *channel;
+struct p2p_snep_data {
        uint8_t *nfc_data;
        uint32_t nfc_data_length;
        uint32_t nfc_data_current_length;
@@ -87,7 +81,7 @@ struct p2p_snep_resp_frame {
        uint8_t info[];
 } __attribute__((packed));
 
-static struct p2p_snep_channel snep_server;
+static struct p2p_snep_data snep_data;
 
 static void snep_response_noinfo(int client_fd, uint8_t response)
 {
@@ -101,30 +95,31 @@ static void snep_response_noinfo(int client_fd, uint8_t response)
        send(client_fd, &resp, sizeof(resp), 0);
 }
 
-static void snep_read_ndef(int client_fd, int ndef_length,
-                                       near_bool_t allocate)
+static void snep_read_ndef(int client_fd,
+               uint32_t adapter_idx, uint32_t target_idx,
+               near_tag_io_cb cb, int ndef_length, near_bool_t allocate)
 {
        int bytes_recv, remaining_bytes;
 
        DBG("");
 
        if (allocate == TRUE) {
-               g_free(snep_server.nfc_data);
+               g_free(snep_data.nfc_data);
 
-               snep_server.nfc_data = g_try_malloc0(ndef_length + TLV_SIZE);
-               if (snep_server.nfc_data == NULL)
+               snep_data.nfc_data = g_try_malloc0(ndef_length + TLV_SIZE);
+               if (snep_data.nfc_data == NULL)
                        return;
 
-               snep_server.nfc_data[0] = TLV_NDEF;
-               snep_server.nfc_data[1] = ndef_length;
+               snep_data.nfc_data[0] = TLV_NDEF;
+               snep_data.nfc_data[1] = ndef_length;
 
-               snep_server.nfc_data_length = ndef_length + TLV_SIZE;
-               snep_server.nfc_data_current_length = TLV_SIZE;
-               snep_server.nfc_data_ptr = snep_server.nfc_data + TLV_SIZE;
+               snep_data.nfc_data_length = ndef_length + TLV_SIZE;
+               snep_data.nfc_data_current_length = TLV_SIZE;
+               snep_data.nfc_data_ptr = snep_data.nfc_data + TLV_SIZE;
        }
 
-       remaining_bytes = snep_server.nfc_data_length - snep_server.nfc_data_current_length;
-       bytes_recv = recv(client_fd, snep_server.nfc_data_ptr, remaining_bytes, 0);
+       remaining_bytes = snep_data.nfc_data_length - snep_data.nfc_data_current_length;
+       bytes_recv = recv(client_fd, snep_data.nfc_data_ptr, remaining_bytes, 0);
        if (bytes_recv < 0) {
                near_error("Could not read SNEP NDEF buffer %d", bytes_recv);
                return;
@@ -132,34 +127,34 @@ static void snep_read_ndef(int client_fd, int ndef_length,
 
        DBG("Received %d bytes", bytes_recv);
 
-       snep_server.nfc_data_current_length += bytes_recv;
+       snep_data.nfc_data_current_length += bytes_recv;
 
-       if (snep_server.nfc_data_length == snep_server.nfc_data_current_length) {
+       if (snep_data.nfc_data_length == snep_data.nfc_data_current_length) {
                struct near_tag *tag;
                size_t tag_length;
                uint8_t *nfc_data;
 
-               snep_server.nfc_data_current_length = 0;
+               snep_data.nfc_data_current_length = 0;
                snep_response_noinfo(client_fd, SNEP_RESP_SUCCESS);
-               tag = near_target_add_tag(snep_server.adapter_idx,
-                                       snep_server.target_idx,
-                                       snep_server.nfc_data_length);
+               tag = near_target_add_tag(adapter_idx, target_idx,
+                                       snep_data.nfc_data_length);
                if (tag == NULL) {
-                       g_free(snep_server.nfc_data);
+                       g_free(snep_data.nfc_data);
                        return;
                }
 
                nfc_data = near_tag_get_data(tag, &tag_length);
-               memcpy(nfc_data, snep_server.nfc_data, tag_length);
+               memcpy(nfc_data, snep_data.nfc_data, tag_length);
 
-               near_tlv_parse(tag, snep_server.cb, nfc_data, tag_length);
-               g_free(snep_server.nfc_data);
+               near_tlv_parse(tag, cb, nfc_data, tag_length);
+               g_free(snep_data.nfc_data);
        } else {
                snep_response_noinfo(client_fd, SNEP_RESP_CONTINUE);
        }
 }
 
-static void snep_read(int client_fd)
+static int snep_read(int client_fd, uint32_t adapter_idx, uint32_t target_idx,
+               near_tag_io_cb cb)
 {
        struct p2p_snep_req_frame frame;
        int bytes_recv;
@@ -168,15 +163,16 @@ static void snep_read(int client_fd)
        DBG("");
 
        /* If current length is not 0, we're waiting for a fragment */
-       if (snep_server.nfc_data_current_length > 0) {
-               snep_read_ndef(client_fd, 0, FALSE);
-               return;
+       if (snep_data.nfc_data_current_length > 0) {
+               snep_read_ndef(client_fd, adapter_idx, target_idx, cb,
+                                                               0, FALSE);
+               return 0;
        }
 
        bytes_recv = recv(client_fd, &frame, sizeof(frame), 0);
        if (bytes_recv < 0) {
                near_error("Could not read SNEP frame %d", bytes_recv);
-               return;
+               return bytes_recv;
        }
 
        DBG("Request 0x%x", frame.request);
@@ -186,102 +182,29 @@ static void snep_read(int client_fd)
        case SNEP_REQ_GET:
                near_error("Unsupported SNEP request code");
                snep_response_noinfo(client_fd, SNEP_RESP_NOT_IMPL);
-               break;
+               return -EOPNOTSUPP;
        case SNEP_REQ_PUT:
                ndef_length = GINT_FROM_BE(frame.length);
-               snep_read_ndef(client_fd, ndef_length, TRUE);
-       }
-}
-
-static gboolean snep_listener_event(GIOChannel *channel, GIOCondition condition,
-                                                       gpointer user_data)
-{
-       struct sockaddr_nfc_llcp client_addr;
-       int server_fd, client_fd;
-       socklen_t client_addr_len;
-
-       DBG("condition 0x%x", condition);
-
-       if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
-               if (snep_server.watch > 0)
-                       g_source_remove(snep_server.watch);
-               snep_server.watch = 0;
-
-               near_error("Error with SNEP server channel");
-
-               return FALSE;
+               snep_read_ndef(client_fd, adapter_idx, target_idx, cb,
+                               ndef_length, TRUE);
+               break;
        }
 
-       if (condition & G_IO_IN) {
-               server_fd = g_io_channel_unix_get_fd(channel);
-
-               client_fd = accept(server_fd, (struct sockaddr *)&client_addr,
-                                                       &client_addr_len);
-               if (client_fd < 0) {
-                       near_error("SNEP accept failed %d", client_fd);
-
-                       close(server_fd);
-                       return FALSE;
-               }
-
-               DBG("client dsap %d ssap %d",
-                       client_addr.dsap, client_addr.ssap);
-
-               snep_read(client_fd);
-
-               close(client_fd);
+       return 0;
+}
 
-               return FALSE;
-       }
+struct near_p2p_driver snep_driver = {
+       .name = "SNEP",
+       .service_name = "urn:nfc:sn:snep",
+       .read = snep_read,
+};
 
-       return FALSE;
+int snep_init(void)
+{
+       return near_p2p_register(&snep_driver);
 }
 
-int snep_bind(uint32_t adapter_idx, uint32_t target_idx,
-                                       near_tag_io_cb cb)
+void snep_exit(void)
 {
-       int err;
-       struct sockaddr_nfc_llcp addr;
-
-       DBG("");
-
-       snep_server.adapter_idx = adapter_idx;
-       snep_server.target_idx = target_idx;
-       snep_server.cb = cb;
-       snep_server.fd = socket(AF_NFC, SOCK_STREAM, NFC_SOCKPROTO_LLCP);
-       if (snep_server.fd < 0)
-               return -errno;
-
-       memset(&addr, 0, sizeof(struct sockaddr_nfc_llcp));
-       addr.sa_family = AF_NFC;
-       addr.dev_idx = adapter_idx;
-       addr.nfc_protocol = NFC_PROTO_NFC_DEP;
-       addr.service_name_len = strlen(SNEP_SN);
-       strcpy(addr.service_name, SNEP_SN);
-
-       err = bind(snep_server.fd, (struct sockaddr *)&addr, sizeof(struct sockaddr_nfc_llcp));
-       if (err < 0) {
-               near_error("SNEP bind failed %d", err);
-
-               close(snep_server.fd);
-               return err;
-       }
-
-       err = listen(snep_server.fd, 10);
-       if (err < 0) {
-               near_error("SNEP listen failed %d", err);
-
-               close(snep_server.fd);
-               return err;
-       }
-
-       snep_server.channel = g_io_channel_unix_new(snep_server.fd);
-       g_io_channel_set_close_on_unref(snep_server.channel, TRUE);
-
-       snep_server.watch = g_io_add_watch(snep_server.channel,
-                               G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
-                               snep_listener_event,
-                               (gpointer) &snep_server.channel);
-
-       return 0;
+       near_p2p_unregister(&snep_driver);
 }