Fix use of strncpy()
[openobex:mainline.git] / lib / transport / irobex.c
1 /**
2         \file irobex.c
3         IrOBEX, IrDA transport for OBEX.
4         OpenOBEX library - Free implementation of the Object Exchange protocol.
5
6         Copyright (c) 1999 Dag Brattli, All Rights Reserved.
7         Copyright (c) 2000 Pontus Fuchs, All Rights Reserved.
8
9         OpenOBEX is free software; you can redistribute it and/or modify
10         it under the terms of the GNU Lesser General Public License as
11         published by the Free Software Foundation; either version 2.1 of
12         the License, or (at your option) any later version.
13
14         This program is distributed in the hope that it will be useful,
15         but WITHOUT ANY WARRANTY; without even the implied warranty of
16         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17         GNU Lesser General Public License for more details.
18
19         You should have received a copy of the GNU Lesser General Public
20         License along with OpenOBEX. If not, see <http://www.gnu.org/>.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #ifdef _WIN32
28 #include <winsock2.h>
29
30 #include "irda_wrap.h"
31
32 #else /* _WIN32 */
33 /* Linux case */
34
35 #include <string.h>
36 #include <unistd.h>
37 #include <stdio.h>              /* perror */
38 #include <errno.h>              /* errno and EADDRNOTAVAIL */
39 #include <netinet/in.h>
40 #include <sys/socket.h>
41 #include <stdlib.h>
42
43 #include "irda_wrap.h"
44
45 #ifndef AF_IRDA
46 #define AF_IRDA 23
47 #endif /* AF_IRDA */
48 #endif /* _WIN32 */
49
50
51 #include "obex_main.h"
52 #include "irobex.h"
53 #include "obex_transport_sock.h"
54
55 struct irobex_data {
56         struct obex_sock *sock;
57 };
58
59 static void * irobex_create(void)
60 {
61         return calloc(1, sizeof(struct irobex_data));
62 }
63
64 static bool irobex_init (obex_t *self)
65 {
66         struct irobex_data *data = self->trans->data;
67         socklen_t len = sizeof(struct sockaddr_irda);
68
69         if (data == NULL)
70                 return false;
71
72         data->sock = obex_transport_sock_create(AF_IRDA, 0,
73                                                 len, self->init_flags);
74         if (data->sock == NULL) {
75                 free(data);
76                 return false;
77         }
78
79         return true;
80 }
81
82 static void irobex_cleanup (obex_t *self)
83 {
84         struct irobex_data *data = self->trans->data;
85
86         if (data->sock)
87                 obex_transport_sock_destroy(data->sock);
88         free(data);     
89 }
90
91 /*
92  * Function irobex_no_addr (addr)
93  *
94  *    Check if the address is not valid for connection
95  *
96  */
97 static bool irobex_no_addr(struct sockaddr_irda *addr)
98 {
99 #ifndef _WIN32
100         return ((addr->sir_addr == 0x0) || (addr->sir_addr == 0xFFFFFFFF));
101 #else
102         return (((addr->irdaDeviceID[0] == 0x00) &&
103                  (addr->irdaDeviceID[1] == 0x00) &&
104                  (addr->irdaDeviceID[2] == 0x00) &&
105                  (addr->irdaDeviceID[3] == 0x00)) ||
106                 ((addr->irdaDeviceID[0] == 0xFF) &&
107                  (addr->irdaDeviceID[1] == 0xFF) &&
108                  (addr->irdaDeviceID[2] == 0xFF) &&
109                  (addr->irdaDeviceID[3] == 0xFF)));
110 #endif /* _WIN32 */
111 }
112
113 static bool irobex_query_ias(obex_t *self, uint32_t addr, const char* class_name)
114 {
115         int err;
116         struct irda_ias_set ias_query;
117         socklen_t len = sizeof(ias_query);
118         socket_t fd;
119
120         memset(&ias_query, 0, sizeof(ias_query));
121
122         /* Ask if the requested service exist on this device */
123 #ifndef _WIN32
124         ias_query.daddr = addr;
125         strncpy(ias_query.irda_class_name, class_name, IAS_MAX_CLASSNAME-1);
126         strncpy(ias_query.irda_attrib_name, "IrDA:TinyTP:LsapSel", IAS_MAX_ATTRIBNAME-1);
127 #else
128         ias_query.irdaDeviceID[0] = (addr >> 24) & 0xFF;
129         ias_query.irdaDeviceID[1] = (addr >> 16) & 0xFF;
130         ias_query.irdaDeviceID[2] = (addr >> 8) & 0xFF;
131         ias_query.irdaDeviceID[3] = addr & 0xFF;
132         strncpy(ias_query.irdaClassName, class_name, IAS_MAX_CLASSNAME-1);
133         strncpy(ias_query.irdaAttribName, "IrDA:TinyTP:LsapSel", IAS_MAX_ATTRIBNAME-1);
134 #endif
135
136         fd = create_stream_socket(AF_IRDA, 0, OBEX_FL_CLOEXEC);
137         if (fd == INVALID_SOCKET)
138                 return false;
139         err = getsockopt(fd, SOL_IRLMP, IRLMP_IAS_QUERY, (void*)&ias_query, &len);
140         close_socket(fd);
141
142 #if defined(_WIN32)
143         if (err == SOCKET_ERROR) {
144                 if (WSAGetLastError() == WSAECONNREFUSED) {
145                         DEBUG(1, ", doesn't have %s\n", class_name);
146                 } else {
147                         DEBUG(1, " <can't query IAS>\n");
148                 }
149                 return false;
150         }
151 #else
152         if (err == -1) {
153                 if (errno == EADDRNOTAVAIL) {
154                         DEBUG(1, ", doesn't have %s\n", class_name);
155                 } else {
156                         DEBUG(1, " <can't query IAS>\n");
157                 }
158                 return false;
159         }
160 #endif
161
162         DEBUG(1, ", has service %s\n", class_name);
163         return true;
164 }
165
166 static bool irobex_set_local_addr(obex_t *self, struct sockaddr *addr, size_t len)
167 {
168         struct irobex_data *data = self->trans->data;
169
170         return obex_transport_sock_set_local(data->sock, addr, len);
171 }
172
173 static bool irobex_set_remote_addr(obex_t *self, struct sockaddr *addr, size_t len)
174 {
175         struct irobex_data *data = self->trans->data;
176
177         return obex_transport_sock_set_remote(data->sock, addr, len);
178 }
179
180 static bool irobex_select_interface(obex_t *self, obex_interface_t *intf)
181 {
182         struct sockaddr_irda addr;
183
184         /* local address */
185         memset(&addr, 0, sizeof(addr));
186         addr.sir_family = AF_IRDA;
187 #ifndef _WIN32
188         addr.sir_addr = intf->irda.local;
189 #else
190         memset(addr.irdaDeviceID, 0, sizeof(addr.irdaDeviceID));
191 #endif
192         if (!irobex_set_local_addr(self, (struct sockaddr *)&addr, sizeof(addr)))
193                 return false;
194
195         /* remote address */
196         memset(&addr, 0, sizeof(addr));
197         addr.sir_family = AF_IRDA;
198         strncpy(addr.sir_name, intf->irda.service, sizeof(addr.sir_name)-1);
199 #ifndef _WIN32
200         addr.sir_lsap_sel = LSAP_ANY;
201         addr.sir_addr = intf->irda.remote;
202 #else
203         addr.irdaDeviceID[0] = (intf->irda.remote >> 24) & 0xFF;
204         addr.irdaDeviceID[1] = (intf->irda.remote >> 16) & 0xFF;
205         addr.irdaDeviceID[2] = (intf->irda.remote >> 8) & 0xFF;
206         addr.irdaDeviceID[3] = intf->irda.remote & 0xFF;
207 #endif
208         if (!irobex_set_remote_addr(self, (struct sockaddr *)&addr, sizeof(addr)))
209                 return false;
210
211         return true;
212 }
213
214 /*
215  * Function irobex_prepare_connect (self, service)
216  *
217  *    Prepare for IR-connect
218  *
219  */
220 void irobex_prepare_connect(obex_t *self, const char *service)
221 {
222         int i = 0;
223
224         obex_transport_enumerate(self);
225         if (self->interfaces_number == 0) {
226                 DEBUG(1, "No devices in range\n");
227                 return;
228         }
229
230         if (service == NULL)
231                 service = "OBEX";
232
233         /* Do we want to filter devices based on IAS ? */
234         if (self->init_flags & OBEX_FL_FILTERIAS) {
235                 for (; i < self->interfaces_number; ++i) {
236                         obex_irda_intf_t *intf = &self->interfaces[i].irda;
237                         if (irobex_query_ias(self, intf->remote, service))
238                                 break;
239                 }
240                 if (i >= self->interfaces_number)
241                         return;
242         }
243         self->interfaces[i].irda.service = service;
244         irobex_select_interface(self, &self->interfaces[i]);
245         self->interfaces[i].irda.service = NULL;
246 }
247
248 /*
249  * Function irobex_prepare_listen (self, service)
250  *
251  *    Prepare for IR-listen
252  *
253  */
254 void irobex_prepare_listen(obex_t *self, const char *service)
255 {
256         struct sockaddr_irda addr;
257
258         /* Bind local service */
259         addr.sir_family = AF_IRDA;
260 #ifndef _WIN32
261         addr.sir_lsap_sel = LSAP_ANY;
262 #endif /* _WIN32 */
263
264         if (service == NULL)
265                 service = "OBEX";
266         strncpy(addr.sir_name, service, sizeof(addr.sir_name));
267         irobex_set_local_addr(self, (struct sockaddr *)&addr, sizeof(addr));
268 }
269
270 static bool set_listen_sock_opts(socket_t fd)
271 {
272 #ifndef _WIN32
273         /* Hint be we advertise */
274         unsigned char hints[4] = {
275                 HINT_EXTENSION, HINT_OBEX, 0, 0,
276         };
277
278         /* Tell the stack about it.
279          * This command is not supported by older kernels,
280          * so ignore any errors!
281          */
282         setsockopt(fd, SOL_IRLMP, IRLMP_HINTS_SET, hints, sizeof(hints));
283
284 #else /* _WIN32 */
285         /* The registry must be changed to set the hint bit. */
286 #endif /* _WIN32 */
287
288         return true;
289 }
290
291 /*
292  * Function irobex_listen (self)
293  *
294  *    Listen for incoming connections.
295  *
296  */
297 static bool irobex_listen(obex_t *self)
298 {
299         struct irobex_data *data = self->trans->data;
300
301         DEBUG(4, "\n");
302
303         data->sock->set_sock_opts = &set_listen_sock_opts;
304
305         return obex_transport_sock_listen(data->sock);
306 }
307
308 /*
309  * Function irobex_accept (self)
310  *
311  *    Accept an incoming connection.
312  *
313  * Note : don't close the server socket here, so apps may want to continue
314  * using it...
315  */
316 static bool irobex_accept(obex_t *self, const obex_t *server)
317 {
318         struct irobex_data *server_data = server->trans->data;
319         struct irobex_data *data = self->trans->data;
320
321         if (data == NULL)
322                 return false;
323
324         data->sock = obex_transport_sock_accept(server_data->sock);
325         if (data->sock == NULL)
326                 return false;
327
328         return true;
329 }
330
331 /*
332  * Function irobex_find_interfaces()
333  *
334  *    Try to discover some remote device(s) that we can connect to
335  *
336  * Note : we optionally can do a first filtering on the Obex hint bit,
337  * and then we can verify that the device does have the requested service...
338  * Note : in this function, the memory allocation for the discovery log
339  * is done "the right way", so that it's safe and we don't leak memory...
340  * Jean II
341  */
342 static int irobex_find_interfaces(obex_t *self, obex_interface_t **interfaces)
343 {
344         struct irda_device_list *list;
345         struct irda_device_info *dev;
346         unsigned char buf[sizeof(*list) + ((MAX_DEVICES-1) * sizeof(*dev))];
347         socklen_t len = sizeof(buf);
348         int count = 0;
349         socket_t fd = create_stream_socket(AF_IRDA, 0, OBEX_FL_CLOEXEC);
350         int i;
351         uint32_t k = 0;
352
353         if (fd == INVALID_SOCKET)
354                 goto out;
355
356 #ifndef _WIN32
357         /* Hint bit filtering, if possible */
358         if (self->init_flags & OBEX_FL_FILTERHINT) {
359                 unsigned char hints[4] = {
360                         HINT_EXTENSION, HINT_OBEX, 0, 0,
361                 };
362                 int err;
363
364                 /* Set the filter used for performing discovery */
365                 err = setsockopt(fd, SOL_IRLMP, IRLMP_HINT_MASK_SET,
366                                                         hints, sizeof(hints));
367                 if (err < 0) {
368                         perror("setsockopt");
369                         goto out;
370                 }
371         }
372 #endif
373
374         /* Perform a discovery and get device list */
375         if (getsockopt(fd, SOL_IRLMP, IRLMP_ENUMDEVICES, (char *) buf, &len))
376                 goto done;
377
378         list = (struct irda_device_list *) buf;
379 #ifndef _WIN32
380         count = (int) list->len;
381         dev = list->dev;
382 #else
383         count = (int) list->numDevice;
384         dev = list->Device;
385 #endif
386         if (count <= 0)
387                 goto done;
388
389         *interfaces = calloc(count, sizeof(**interfaces));
390
391         DEBUG(1, "Discovered %u devices:\n", count);
392         for (i = 0; i < count; ++i) {
393                 obex_irda_intf_t *intf = &((*interfaces)+k)->irda;
394
395 #ifndef _WIN32
396                 intf->local = dev[i].saddr;
397                 intf->remote = dev[i].daddr;
398                 intf->charset = dev[i].charset;
399                 /* allocate enough space to make sure the string is
400                  * zero-terminated
401                  */
402                 intf->info = calloc(sizeof(dev[i].info)+2, 1);
403                 if (intf->info)
404                         memcpy(intf->info, dev[i].info, sizeof(dev[i].info));
405
406                 intf->hints[0] = dev[i].hints[0];
407                 intf->hints[1] = dev[i].hints[1];
408 #else
409                 if ((self->init_flags & OBEX_FL_FILTERHINT) &&
410                                 ((dev[i].irdaDeviceHints1 & LM_HB_Extension) == 0))
411                         continue;
412
413                 if ((dev[i].irdaDeviceHints2 & 0x20) == 0)
414                         continue;
415
416                 intf->remote = dev[i].irdaDeviceID[3]
417                                         | dev[i].irdaDeviceID[2] << 8
418                                         | dev[i].irdaDeviceID[1] << 16
419                                         | dev[i].irdaDeviceID[0] << 24;
420                 intf->charset = dev[i].irdaCharSet;
421                 /* allocate enough space to make sure the
422                  * string is zero-terminated */
423                 intf->info = calloc(sizeof(dev[i].irdaDeviceName)+2, 1);
424                 if (intf->info)
425                         memcpy(intf->info, dev[i].irdaDeviceName,
426                                                 sizeof(dev[i].irdaDeviceName));
427                 intf->hints[0] = dev[i].irdaDeviceHints1;
428                 intf->hints[1] = dev[i].irdaDeviceHints2;
429 #endif
430                 ++k;
431                 DEBUG(1, "  [%d] daddr: 0x%08x\n", i+1, intf->remote);
432         }
433
434         count = k;
435
436 done:
437         if (count == 0)
438                 DEBUG(1, "didn't find any OBEX devices!\n");
439
440 out:
441         close_socket(fd);
442         return count;
443 }
444
445 static void irobex_free_interface(obex_interface_t *intf)
446 {
447         if (intf) {
448                 if (intf->irda.info) {
449                         free(intf->irda.info);
450                         intf->irda.info = NULL;
451                 }
452         }
453 }
454
455 /*
456  * Function irobex_irda_connect_request (self)
457  *
458  *    Open the TTP connection
459  *
460  */
461 static bool irobex_connect_request(obex_t *self)
462 {
463         struct irobex_data *data = self->trans->data;
464
465         DEBUG(4, "\n");
466
467         /* Check if the application did supply a valid address. */
468         if (irobex_no_addr((struct sockaddr_irda *)&data->sock->remote))
469                 return false;
470
471         return obex_transport_sock_connect(data->sock);
472 }
473
474 /*
475  * Function irobex_disconnect (self)
476  *
477  *    Shutdown the IrTTP link
478  *
479  */
480 static bool irobex_disconnect(obex_t *self)
481 {
482         struct irobex_data *data = self->trans->data;
483
484         DEBUG(4, "\n");
485
486         return obex_transport_sock_disconnect(data->sock);
487 }
488
489 static result_t irobex_handle_input(obex_t *self)
490 {
491         struct irobex_data *data = self->trans->data;
492
493         DEBUG(4, "\n");
494
495         return obex_transport_sock_wait(data->sock, self->trans->timeout);
496 }
497
498 static ssize_t irobex_write(obex_t *self, struct databuffer *msg)
499 {
500         struct obex_transport *trans = self->trans;
501         struct irobex_data *data = self->trans->data;
502
503         DEBUG(4, "\n");
504
505         return obex_transport_sock_send(data->sock, msg, trans->timeout);
506 }
507
508 static ssize_t irobex_read(obex_t *self, void *buf, int buflen)
509 {
510         struct irobex_data *data = self->trans->data;
511
512         DEBUG(4, "\n");
513
514         return obex_transport_sock_recv(data->sock, buf, buflen);
515 }
516
517 static int irobex_get_fd(obex_t *self)
518 {
519         struct irobex_data *data = self->trans->data;
520
521         return (int)obex_transport_sock_get_fd(data->sock);
522 }
523
524 static struct obex_transport_ops irobex_transport_ops = {
525         &irobex_create,
526         &irobex_init,
527         &irobex_cleanup,
528
529         &irobex_handle_input,
530         &irobex_write,
531         &irobex_read,
532         &irobex_disconnect,
533
534         &irobex_get_fd,
535         &irobex_set_local_addr,
536         &irobex_set_remote_addr,
537         {
538                 &irobex_listen,
539                 &irobex_accept,
540         },
541         {
542                 &irobex_connect_request,
543                 &irobex_find_interfaces,
544                 &irobex_free_interface,
545                 &irobex_select_interface,
546         },
547 };
548
549 struct obex_transport * irobex_transport_create(void)
550 {
551         return obex_transport_create(&irobex_transport_ops);
552 }