OSDN Git Service

Remove obsolete LOCAL_MODULE_TAGS
[android-x86/external-bluetooth-bluez.git] / tools / obex-client-tool.c
1 /*
2  *
3  *  OBEX library with GLib integration
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 <sys/types.h>
27 #include <sys/socket.h>
28 #include <fcntl.h>
29 #include <sys/un.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <stdio.h>
35
36 #include <readline/readline.h>
37 #include <readline/history.h>
38
39 #include "gobex/gobex.h"
40 #include "btio/btio.h"
41
42 static GMainLoop *main_loop = NULL;
43 static GObex *obex = NULL;
44
45 static gboolean option_packet = FALSE;
46 static gboolean option_bluetooth = FALSE;
47 static char *option_source = NULL;
48 static char *option_dest = NULL;
49 static int option_channel = -1;
50 static int option_imtu = -1;
51 static int option_omtu = -1;
52
53 static void sig_term(int sig)
54 {
55         g_print("Terminating due to signal %d\n", sig);
56         g_main_loop_quit(main_loop);
57 }
58
59 static GOptionEntry options[] = {
60         { "unix", 'u', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE,
61                         &option_bluetooth, "Use a UNIX socket" },
62         { "bluetooth", 'b', 0, G_OPTION_ARG_NONE,
63                         &option_bluetooth, "Use Bluetooth" },
64         { "source", 's', 0, G_OPTION_ARG_STRING,
65                         &option_source, "Bluetooth adapter address",
66                         "00:..." },
67         { "destination", 'd', 0, G_OPTION_ARG_STRING,
68                         &option_dest, "Remote bluetooth address",
69                         "00:..." },
70         { "channel", 'c', 0, G_OPTION_ARG_INT,
71                         &option_channel, "Transport channel", "CHANNEL" },
72         { "packet", 'p', 0, G_OPTION_ARG_NONE,
73                         &option_packet, "Packet based transport" },
74         { "stream", 's', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE,
75                         &option_packet, "Stream based transport" },
76         { "input-mtu", 'i', 0, G_OPTION_ARG_INT,
77                         &option_imtu, "Transport input MTU", "MTU" },
78         { "output-mtu", 'o', 0, G_OPTION_ARG_INT,
79                         &option_omtu, "Transport output MTU", "MTU" },
80         { NULL },
81 };
82
83 static void conn_complete(GObex *obex, GError *err, GObexPacket *rsp,
84                                                         gpointer user_data)
85 {
86         if (err != NULL)
87                 g_print("Connect failed: %s\n", err->message);
88         else
89                 g_print("Connect succeeded\n");
90 }
91
92 static void cmd_connect(int argc, char **argv)
93 {
94         g_obex_connect(obex, conn_complete, NULL, NULL, G_OBEX_HDR_INVALID);
95 }
96
97 struct transfer_data {
98         int fd;
99 };
100
101 static void transfer_complete(GObex *obex, GError *err, gpointer user_data)
102 {
103         struct transfer_data *data = user_data;
104
105         if (err != NULL)
106                 g_printerr("failed: %s\n", err->message);
107         else
108                 g_print("transfer succeeded\n");
109
110         close(data->fd);
111         g_free(data);
112 }
113
114 static gssize put_data_cb(void *buf, gsize len, gpointer user_data)
115 {
116         struct transfer_data *data = user_data;
117
118         return read(data->fd, buf, len);
119 }
120
121 static void cmd_put(int argc, char **argv)
122 {
123         struct transfer_data *data;
124         GError *err = NULL;
125         int fd;
126
127         if (argc < 2) {
128                 g_printerr("Filename required\n");
129                 return;
130         }
131
132         fd = open(argv[1], O_RDONLY | O_NOCTTY, 0);
133         if (fd < 0) {
134                 g_printerr("open: %s\n", strerror(errno));
135                 return;
136         }
137
138         data = g_new0(struct transfer_data, 1);
139         data->fd = fd;
140
141         g_obex_put_req(obex, put_data_cb, transfer_complete, data, &err,
142                                                 G_OBEX_HDR_NAME, argv[1],
143                                                 G_OBEX_HDR_INVALID);
144         if (err != NULL) {
145                 g_printerr("put failed: %s\n", err->message);
146                 g_error_free(err);
147                 close(data->fd);
148                 g_free(data);
149         }
150 }
151
152 static gboolean get_data_cb(const void *buf, gsize len, gpointer user_data)
153 {
154         struct transfer_data *data = user_data;
155
156         if (write(data->fd, buf, len) < 0) {
157                 g_printerr("write: %s\n", strerror(errno));
158                 return FALSE;
159         }
160
161         return TRUE;
162 }
163
164 static void cmd_get(int argc, char **argv)
165 {
166         struct transfer_data *data;
167         GError *err = NULL;
168         int fd;
169
170         if (argc < 2) {
171                 g_printerr("Filename required\n");
172                 return;
173         }
174
175         fd = open(argv[1], O_WRONLY | O_CREAT | O_NOCTTY, 0600);
176         if (fd < 0) {
177                 g_printerr("open: %s\n", strerror(errno));
178                 return;
179         }
180
181         data = g_new0(struct transfer_data, 1);
182         data->fd = fd;
183
184         g_obex_get_req(obex, get_data_cb, transfer_complete, data, &err,
185                                                 G_OBEX_HDR_NAME, argv[1],
186                                                 G_OBEX_HDR_INVALID);
187         if (err != NULL) {
188                 g_printerr("get failed: %s\n", err->message);
189                 g_error_free(err);
190                 close(data->fd);
191                 g_free(data);
192         }
193 }
194
195 static void cmd_help(int argc, char **argv);
196
197 static void cmd_exit(int argc, char **argv)
198 {
199         g_main_loop_quit(main_loop);
200 }
201
202 static struct {
203         const char *cmd;
204         void (*func)(int argc, char **argv);
205         const char *params;
206         const char *desc;
207 } commands[] = {
208         { "help",       cmd_help,       "",             "Show this help"},
209         { "exit",       cmd_exit,       "",             "Exit application" },
210         { "quit",       cmd_exit,       "",             "Exit application" },
211         { "connect",    cmd_connect,    "[target]",     "OBEX Connect" },
212         { "put",        cmd_put,        "<file>",       "Send a file" },
213         { "get",        cmd_get,        "<file>",       "Receive a file" },
214         { NULL },
215 };
216
217 static void cmd_help(int argc, char **argv)
218 {
219         int i;
220
221         for (i = 0; commands[i].cmd; i++)
222                 printf("%-15s %-30s %s\n", commands[i].cmd,
223                                 commands[i].params, commands[i].desc);
224 }
225
226 static void parse_line(char *line_read)
227 {
228         char **argvp;
229         int argcp;
230         int i;
231
232         if (line_read == NULL) {
233                 g_print("\n");
234                 g_main_loop_quit(main_loop);
235                 return;
236         }
237
238         line_read = g_strstrip(line_read);
239
240         if (*line_read == '\0') {
241                 free(line_read);
242                 return;
243         }
244
245         add_history(line_read);
246
247         g_shell_parse_argv(line_read, &argcp, &argvp, NULL);
248
249         free(line_read);
250
251         for (i = 0; commands[i].cmd; i++)
252                 if (strcasecmp(commands[i].cmd, argvp[0]) == 0)
253                         break;
254
255         if (commands[i].cmd)
256                 commands[i].func(argcp, argvp);
257         else
258                 g_print("%s: command not found\n", argvp[0]);
259
260         g_strfreev(argvp);
261 }
262
263 static gboolean prompt_read(GIOChannel *chan, GIOCondition cond,
264                                                         gpointer user_data)
265 {
266         if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
267                 g_main_loop_quit(main_loop);
268                 return FALSE;
269         }
270
271         rl_callback_read_char();
272
273         return TRUE;
274 }
275
276 static void disconn_func(GObex *obex, GError *err, gpointer user_data)
277 {
278         g_printerr("Disconnected: %s\n", err ? err->message : "(no error)");
279         g_main_loop_quit(main_loop);
280 }
281
282 static void transport_connect(GIOChannel *io, GObexTransportType transport)
283 {
284         GIOChannel *input;
285         GIOCondition events;
286
287         g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
288         g_io_channel_set_close_on_unref(io, TRUE);
289
290         obex = g_obex_new(io, transport, option_imtu, option_omtu);
291         g_obex_set_disconnect_function(obex, disconn_func, NULL);
292
293         input = g_io_channel_unix_new(STDIN_FILENO);
294         g_io_channel_set_close_on_unref(input, TRUE);
295         events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
296         g_io_add_watch(input, events, prompt_read, NULL);
297         g_io_channel_unref(input);
298         rl_callback_handler_install("client> ", parse_line);
299 }
300
301 static GIOChannel *unix_connect(GObexTransportType transport)
302 {
303         GIOChannel *io;
304         struct sockaddr_un addr = {
305                 AF_UNIX, "\0/gobex/server"
306         };
307         int sk, err, sock_type;
308
309         if (option_packet)
310                 sock_type = SOCK_SEQPACKET;
311         else
312                 sock_type = SOCK_STREAM;
313
314         sk = socket(PF_LOCAL, sock_type, 0);
315         if (sk < 0) {
316                 err = errno;
317                 g_printerr("Can't create unix socket: %s (%d)\n",
318                                                 strerror(err), err);
319                 return NULL;
320         }
321
322         if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
323                 err = errno;
324                 g_printerr("connect: %s (%d)\n", strerror(err), err);
325                 return NULL;
326         }
327
328         io = g_io_channel_unix_new(sk);
329
330         g_print("Unix socket created: %d\n", sk);
331
332         transport_connect(io, transport);
333
334         return io;
335 }
336
337 static void conn_callback(GIOChannel *io, GError *err, gpointer user_data)
338 {
339         GObexTransportType transport = GPOINTER_TO_UINT(user_data);
340
341         if (err != NULL) {
342                 g_printerr("%s\n", err->message);
343                 return;
344         }
345
346         g_print("Bluetooth socket connected\n");
347
348         transport_connect(io, transport);
349 }
350
351 static GIOChannel *l2cap_connect(GObexTransportType transport, GError **err)
352 {
353         if (option_source)
354                 return bt_io_connect(conn_callback,
355                                         GUINT_TO_POINTER(transport),
356                                         NULL, err,
357                                         BT_IO_OPT_SOURCE, option_source,
358                                         BT_IO_OPT_DEST, option_dest,
359                                         BT_IO_OPT_PSM, option_channel,
360                                         BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
361                                         BT_IO_OPT_OMTU, option_omtu,
362                                         BT_IO_OPT_IMTU, option_imtu,
363                                         BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
364                                         BT_IO_OPT_INVALID);
365
366         return bt_io_connect(conn_callback,
367                                         GUINT_TO_POINTER(transport),
368                                         NULL, err,
369                                         BT_IO_OPT_DEST, option_dest,
370                                         BT_IO_OPT_PSM, option_channel,
371                                         BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
372                                         BT_IO_OPT_OMTU, option_omtu,
373                                         BT_IO_OPT_IMTU, option_imtu,
374                                         BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
375                                         BT_IO_OPT_INVALID);
376 }
377
378 static GIOChannel *rfcomm_connect(GObexTransportType transport, GError **err)
379 {
380         if (option_source)
381                 return bt_io_connect(conn_callback,
382                                         GUINT_TO_POINTER(transport),
383                                         NULL, err,
384                                         BT_IO_OPT_SOURCE, option_source,
385                                         BT_IO_OPT_DEST, option_dest,
386                                         BT_IO_OPT_CHANNEL, option_channel,
387                                         BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
388                                         BT_IO_OPT_INVALID);
389
390         return bt_io_connect(conn_callback,
391                                         GUINT_TO_POINTER(transport),
392                                         NULL, err,
393                                         BT_IO_OPT_DEST, option_dest,
394                                         BT_IO_OPT_CHANNEL, option_channel,
395                                         BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
396                                         BT_IO_OPT_INVALID);
397 }
398
399 static GIOChannel *bluetooth_connect(GObexTransportType transport)
400 {
401         GIOChannel *io;
402         GError *err = NULL;
403
404         if (option_dest == NULL || option_channel < 0)
405                 return NULL;
406
407         if (option_channel > 31)
408                 io = l2cap_connect(transport, &err);
409         else
410                 io = rfcomm_connect(transport, &err);
411
412         if (io != NULL)
413                 return io;
414
415         g_printerr("%s\n", err->message);
416         g_error_free(err);
417         return NULL;
418 }
419
420 int main(int argc, char *argv[])
421 {
422         GOptionContext *context;
423         GError *err = NULL;
424         struct sigaction sa;
425         GIOChannel *io;
426         GObexTransportType transport;
427
428         context = g_option_context_new(NULL);
429         g_option_context_add_main_entries(context, options, NULL);
430
431         g_option_context_parse(context, &argc, &argv, &err);
432         if (err != NULL) {
433                 g_printerr("%s\n", err->message);
434                 g_error_free(err);
435                 g_option_context_free(context);
436                 exit(EXIT_FAILURE);
437         }
438
439         if (option_packet)
440                 transport = G_OBEX_TRANSPORT_PACKET;
441         else
442                 transport = G_OBEX_TRANSPORT_STREAM;
443
444         if (option_bluetooth)
445                 io = bluetooth_connect(transport);
446         else
447                 io = unix_connect(transport);
448
449         if (io == NULL) {
450                 g_option_context_free(context);
451                 exit(EXIT_FAILURE);
452         }
453
454         memset(&sa, 0, sizeof(sa));
455         sa.sa_handler = sig_term;
456         sigaction(SIGINT, &sa, NULL);
457         sigaction(SIGTERM, &sa, NULL);
458
459         main_loop = g_main_loop_new(NULL, FALSE);
460
461         g_main_loop_run(main_loop);
462
463         rl_callback_handler_remove();
464         clear_history();
465         g_obex_unref(obex);
466         g_option_context_free(context);
467         g_main_loop_unref(main_loop);
468
469         exit(EXIT_SUCCESS);
470 }