Fix p2p bug and various warnings
[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         server_data->client_list = NULL;
133
134         DBG("Closing server socket");
135
136         close(server_data->fd);
137
138         g_free(server_data);
139 }
140
141 static gboolean p2p_listener_event(GIOChannel *channel, GIOCondition condition,
142                                                         gpointer user_data)
143 {
144         struct sockaddr_nfc_llcp client_addr;
145         socklen_t client_addr_len;
146         int server_fd, client_fd;
147         struct p2p_data *client_data, *server_data = user_data;
148         GIOChannel *client_channel;
149         struct near_p2p_driver *driver = server_data->driver;
150
151         DBG("condition 0x%x", condition);
152
153         server_fd = g_io_channel_unix_get_fd(channel);
154
155         if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
156                 if (server_data->watch > 0)
157                         g_source_remove(server_data->watch);
158                 server_data->watch = 0;
159
160                 g_list_free_full(server_data->client_list, free_client_data);
161                 server_data->client_list = NULL;
162
163                 near_error("Error with %s server channel", driver->name);
164
165                 return FALSE;
166         }
167
168         client_addr_len = sizeof(client_addr);
169         client_fd = accept(server_fd, (struct sockaddr *) &client_addr,
170                                                         &client_addr_len);
171         if (client_fd < 0) {
172                 near_error("accept failed %d", client_fd);
173
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         g_io_channel_unref(channel);
268
269         server_list = g_list_append(server_list, server_data);
270
271         return 0;
272 }
273
274 static int p2p_listen(uint32_t adapter_idx, near_device_io_cb cb)
275 {
276         int err = -1;
277         GSList *list;
278
279         for (list = driver_list; list != NULL; list = list->next) {
280                 struct near_p2p_driver *driver = list->data;
281
282                 if (p2p_bind(driver, adapter_idx, cb) == 0)
283                         err = 0;
284         }
285
286         return err;
287 }
288
289 static int p2p_connect(uint32_t adapter_idx, uint32_t target_idx,
290                         struct near_ndef_message *ndef,
291                         near_device_io_cb cb,  struct near_p2p_driver *driver)
292 {
293         int fd, err = 0;
294         struct sockaddr_nfc_llcp addr;
295
296         DBG("");
297
298         fd = socket(AF_NFC, SOCK_STREAM, NFC_SOCKPROTO_LLCP);
299         if (fd < 0)
300                 return -errno;
301
302         memset(&addr, 0, sizeof(struct sockaddr_nfc_llcp));
303         addr.sa_family = AF_NFC;
304         addr.dev_idx = adapter_idx;
305         addr.target_idx = target_idx;
306         addr.nfc_protocol = NFC_PROTO_NFC_DEP;
307         addr.service_name_len = strlen(driver->service_name);
308         strcpy(addr.service_name, driver->service_name);
309
310         err = connect(fd, (struct sockaddr *) &addr,
311                         sizeof(struct sockaddr_nfc_llcp));
312         if (err < 0) {
313                 near_error("Connect failed  %d", err);
314                 close(fd);
315
316                 return err;
317         }
318
319         return fd;
320 }
321
322 static int p2p_push(uint32_t adapter_idx, uint32_t target_idx,
323                         struct near_ndef_message *ndef, char *service_name,
324                         near_device_io_cb cb)
325 {
326         int fd;
327         GSList *list;
328
329         DBG("");
330
331         for (list = driver_list; list != NULL; list = list->next) {
332                 struct near_p2p_driver *driver = list->data;
333
334                 if (strcmp(driver->service_name, service_name) != 0)
335                         continue;
336                 /*
337                  * Because of Android's implementation, we have use SNEP for
338                  * Handover. So, on Handover session, we try to connect to
339                  * the handover service and fallback to SNEP on connect fail.
340                  */
341                 fd = p2p_connect(adapter_idx, target_idx, ndef, cb, driver);
342                 if (fd < 0)
343                         return  p2p_push(adapter_idx, target_idx, ndef,
344                                 (char *) driver->fallback_service_name, cb);
345                 else
346                         return driver->push(fd, adapter_idx, target_idx,
347                                         ndef, cb);
348         }
349
350         return -1;
351 }
352
353 static struct near_device_driver p2p_driver = {
354         .priority       = NEAR_DEVICE_PRIORITY_HIGH,
355         .listen         = p2p_listen,
356         .push           = p2p_push,
357 };
358
359
360 int near_p2p_register(struct near_p2p_driver *driver)
361 {
362         DBG("driver %p name %s", driver, driver->name);
363
364         driver_list = g_slist_prepend(driver_list, driver);
365
366         return 0;
367 }
368
369 void near_p2p_unregister(struct near_p2p_driver *driver)
370 {
371         DBG("driver %p name %s", driver, driver->name);
372
373         driver_list = g_slist_remove(driver_list, driver);
374 }
375
376 static int p2p_init(void)
377 {
378         DBG("");
379
380         npp_init();
381         snep_init();
382         handover_init();
383
384         return near_device_driver_register(&p2p_driver);
385 }
386
387 static void p2p_exit(void)
388 {
389         DBG("");
390
391         g_list_free_full(server_list, free_server_data);
392
393         snep_exit();
394         npp_exit();
395         handover_exit();
396
397         near_device_driver_unregister(&p2p_driver);
398 }
399
400 NEAR_PLUGIN_DEFINE(p2p, "NFC Forum peer to peer mode support", VERSION,
401                 NEAR_PLUGIN_PRIORITY_HIGH, p2p_init, p2p_exit)