f6352a1af96c4c3d23cea72b94c4ded574d14bce
[profile/ivi/neard.git] / plugins / p2p.c
1 /*
2  *
3  *  neard - Near Field Communication manager
4  *
5  *  Copyright (C) 2011  Intel Corporation. All rights reserved.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License version 2 as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <unistd.h>
27 #include <stdint.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <sys/socket.h>
31
32 #include <linux/socket.h>
33 #include <linux/nfc.h>
34
35 #include <near/plugin.h>
36 #include <near/log.h>
37 #include <near/types.h>
38 #include <near/tag.h>
39 #include <near/device.h>
40 #include <near/adapter.h>
41 #include <near/tlv.h>
42 #include <near/ndef.h>
43
44 #include "p2p.h"
45
46 static GSList *driver_list = NULL;
47 static GList *server_list = NULL;
48
49 struct p2p_data {
50         struct near_p2p_driver *driver;
51         uint32_t adapter_idx;
52         uint32_t target_idx;
53         near_device_io_cb cb;
54         int fd;
55         guint watch;
56
57         GList *client_list;
58 };
59
60 static gboolean p2p_client_event(GIOChannel *channel, GIOCondition condition,
61                                                         gpointer user_data)
62 {
63         struct p2p_data *client_data = user_data;
64         near_bool_t more;
65
66         DBG("condition 0x%x", condition);
67
68         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
69                 int err;
70
71                 if (client_data->watch > 0)
72                         g_source_remove(client_data->watch);
73                 client_data->watch = 0;
74
75                 if (condition & (G_IO_NVAL | G_IO_ERR))
76                         err = -EIO;
77                 else
78                         err = 0;
79
80                 if (client_data->driver->close != NULL)
81                         client_data->driver->close(client_data->fd, err);
82
83                 near_error("%s client channel closed",
84                                         client_data->driver->name);
85
86                 return FALSE;
87         }
88
89         more = client_data->driver->read(client_data->fd,
90                                                 client_data->adapter_idx,
91                                                 client_data->target_idx,
92                                                 client_data->cb);
93
94         if (more == FALSE) {
95                 if (client_data->driver->close != NULL)
96                         client_data->driver->close(client_data->fd, 0);
97                 close(client_data->fd);
98         }
99
100         return more;
101 }
102
103 static void free_client_data(gpointer data)
104 {
105         struct p2p_data *client_data;
106
107         DBG("");
108
109         client_data = (struct p2p_data *)data;
110
111         if (client_data->driver->close != NULL)
112                 client_data->driver->close(client_data->fd, 0);
113
114         if (client_data->watch > 0)
115                 g_source_remove(client_data->watch);
116
117         g_free(client_data);
118 }
119
120 static void free_server_data(gpointer data)
121 {
122         struct p2p_data *server_data;
123
124         DBG("");
125
126         server_data = (struct p2p_data *)data;
127
128         if (server_data->watch > 0)
129                 g_source_remove(server_data->watch);
130         server_data->watch = 0;
131         g_list_free_full(server_data->client_list, free_client_data);
132
133         DBG("Closing server socket");
134
135         close(server_data->fd);
136
137         g_free(server_data);
138 }
139
140 static gboolean p2p_listener_event(GIOChannel *channel, GIOCondition condition,
141                                                         gpointer user_data)
142 {
143         struct sockaddr_nfc_llcp client_addr;
144         socklen_t client_addr_len;
145         int server_fd, client_fd;
146         struct p2p_data *client_data, *server_data = user_data;
147         GIOChannel *client_channel;
148         struct near_p2p_driver *driver = server_data->driver;
149
150         DBG("condition 0x%x", condition);
151
152         server_fd = g_io_channel_unix_get_fd(channel);
153
154         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
155                 if (server_data->watch > 0)
156                         g_source_remove(server_data->watch);
157                 server_data->watch = 0;
158                 g_list_free_full(server_data->client_list, free_client_data);
159
160                 close(server_fd);
161
162                 near_error("Error with %s server channel", driver->name);
163
164                 return FALSE;
165         }
166
167         client_addr_len = sizeof(client_addr);
168         client_fd = accept(server_fd, (struct sockaddr *)&client_addr,
169                                                         &client_addr_len);
170         if (client_fd < 0) {
171                 near_error("accept failed %d", client_fd);
172
173                 close(server_fd);
174                 return FALSE;
175         }
176
177         DBG("client dsap %d ssap %d",
178                 client_addr.dsap, client_addr.ssap);
179         DBG("target idx %d", client_addr.target_idx);
180
181         client_data = g_try_malloc0(sizeof(struct p2p_data));
182         if (client_data == NULL) {
183                 close(client_fd);
184                 return FALSE;
185         }
186
187         client_data->driver = server_data->driver;
188         client_data->adapter_idx = server_data->adapter_idx;
189         client_data->target_idx = client_addr.target_idx;
190         client_data->fd = client_fd;
191         client_data->cb = server_data->cb;
192
193         client_channel = g_io_channel_unix_new(client_fd);
194         g_io_channel_set_close_on_unref(client_channel, TRUE);
195
196         client_data->watch = g_io_add_watch(client_channel,
197                                 G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
198                                 p2p_client_event,
199                                 client_data);
200
201         server_data->client_list = g_list_append(server_data->client_list, client_data);
202
203         return TRUE;
204 }
205
206 static int p2p_bind(struct near_p2p_driver *driver, uint32_t adapter_idx,
207                                                         near_device_io_cb cb)
208 {
209         int err, fd;
210         struct sockaddr_nfc_llcp addr;
211         GIOChannel *channel;
212         struct p2p_data *server_data;
213
214         DBG("Binding %s", driver->name);
215
216         fd = socket(AF_NFC, SOCK_STREAM, NFC_SOCKPROTO_LLCP);
217         if (fd < 0)
218                 return -errno;
219
220         memset(&addr, 0, sizeof(struct sockaddr_nfc_llcp));
221         addr.sa_family = AF_NFC;
222         addr.dev_idx = adapter_idx;
223         addr.nfc_protocol = NFC_PROTO_NFC_DEP;
224         addr.service_name_len = strlen(driver->service_name);
225         strcpy(addr.service_name, driver->service_name);
226
227         err = bind(fd, (struct sockaddr *)&addr,
228                         sizeof(struct sockaddr_nfc_llcp));
229         if (err < 0) {
230                 if (errno == EADDRINUSE) {
231                         DBG("%s is already bound", driver->name);
232                         return 0;
233                 }
234
235                 near_error("%s bind failed %d %d", driver->name, err, errno);
236
237                 close(fd);
238                 return err;
239         }
240
241         err = listen(fd, 10);
242         if (err < 0) {
243                 near_error("%s listen failed %d", driver->name, err);
244
245                 close(fd);
246                 return err;
247         }
248
249         server_data = g_try_malloc0(sizeof(struct p2p_data));
250         if (server_data == NULL) {
251                 close(fd);
252                 return -ENOMEM;
253         }
254
255         server_data->driver = driver;
256         server_data->adapter_idx = adapter_idx;
257         server_data->fd = fd;
258         server_data->cb = cb;
259
260         channel = g_io_channel_unix_new(fd);
261         g_io_channel_set_close_on_unref(channel, TRUE);
262
263         server_data->watch = g_io_add_watch(channel,
264                                 G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
265                                 p2p_listener_event,
266                                 (gpointer) server_data);
267
268         server_list = g_list_append(server_list, server_data);
269
270         return 0;
271 }
272
273 static int p2p_listen(uint32_t adapter_idx, near_device_io_cb cb)
274 {
275         int err = 0;
276         GSList *list;
277
278         for (list = driver_list; list != NULL; list = list->next) {
279                 struct near_p2p_driver *driver = list->data;
280
281                 err &= p2p_bind(driver, adapter_idx, cb);
282         }
283
284         return err;
285 }
286
287 static int p2p_connect(uint32_t adapter_idx, uint32_t target_idx,
288                         struct near_ndef_message *ndef,
289                         near_device_io_cb cb,  struct near_p2p_driver *driver)
290 {
291         int fd, err = 0;
292         struct sockaddr_nfc_llcp addr;
293
294         DBG("");
295
296         fd = socket(AF_NFC, SOCK_STREAM, NFC_SOCKPROTO_LLCP);
297         if (fd < 0)
298                 return -errno;
299
300         memset(&addr, 0, sizeof(struct sockaddr_nfc_llcp));
301         addr.sa_family = AF_NFC;
302         addr.dev_idx = adapter_idx;
303         addr.target_idx = target_idx;
304         addr.nfc_protocol = NFC_PROTO_NFC_DEP;
305         addr.service_name_len = strlen(driver->service_name);
306         strcpy(addr.service_name, driver->service_name);
307
308         err = connect(fd, (struct sockaddr *)&addr,
309                         sizeof(struct sockaddr_nfc_llcp));
310         if (err < 0) {
311                 near_error("Connect failed  %d", err);
312                 close(fd);
313
314                 return err;
315         }
316
317         return fd;
318 }
319
320 static int p2p_push(uint32_t adapter_idx, uint32_t target_idx,
321                         struct near_ndef_message *ndef, char *service_name,
322                         near_device_io_cb cb)
323 {
324         int fd;
325         GSList *list;
326
327         DBG("");
328
329         for (list = driver_list; list != NULL; list = list->next) {
330                 struct near_p2p_driver *driver = list->data;
331
332                 if (strcmp(driver->service_name, service_name) != 0)
333                         continue;
334
335                 fd = p2p_connect(adapter_idx, target_idx, ndef, cb, driver);
336                 if (fd < 0)
337                         return fd;
338
339                 return driver->push(fd, adapter_idx, target_idx, ndef, cb);
340         }
341
342         return -1;
343 }
344
345 static struct near_device_driver p2p_driver = {
346         .priority       = NEAR_DEVICE_PRIORITY_HIGH,
347         .listen         = p2p_listen,
348         .push           = p2p_push,
349 };
350
351
352 int near_p2p_register(struct near_p2p_driver *driver)
353 {
354         DBG("driver %p name %s", driver, driver->name);
355
356         driver_list = g_slist_prepend(driver_list, driver);
357
358         return 0;
359 }
360
361 void near_p2p_unregister(struct near_p2p_driver *driver)
362 {
363         DBG("driver %p name %s", driver, driver->name);
364
365         driver_list = g_slist_remove(driver_list, driver);
366 }
367
368 static int p2p_init(void)
369 {
370         DBG("");
371
372         npp_init();
373         snep_init();
374         handover_init();
375
376         return near_device_driver_register(&p2p_driver);
377 }
378
379 static void p2p_exit(void)
380 {
381         DBG("");
382
383         g_list_free_full(server_list, free_server_data);
384
385         snep_exit();
386         npp_exit();
387         handover_exit();
388
389         near_device_driver_unregister(&p2p_driver);
390 }
391
392 NEAR_PLUGIN_DEFINE(p2p, "NFC Forum peer to peer mode support", VERSION,
393                 NEAR_PLUGIN_PRIORITY_HIGH, p2p_init, p2p_exit)