From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Subject: Re: [Bluez-devel] [PATCH] Palm Hotsync over Bluetooth From: Bastien Nocera To: bluez-devel@lists.sourceforge.net Cc: leonerd@leonerd.org.uk, hacker@gnu-designs.com, fpillet@mac.com In-Reply-To: <1127413417.12287.19.camel@blade> References: <1127412332.24352.14.camel@wyatt.hadess.net> <1127413417.12287.19.camel@blade> Content-Type: multipart/mixed; boundary="=-VYrzn/Iq890mDVByUuhY" Message-Id: <1127425906.24352.20.camel@wyatt.hadess.net> Mime-Version: 1.0 Sender: bluez-devel-admin@lists.sourceforge.net Errors-To: bluez-devel-admin@lists.sourceforge.net Reply-To: bluez-devel@lists.sourceforge.net List-Unsubscribe: , List-Id: BlueZ development List-Post: List-Help: List-Subscribe: , List-Archive: Date: Thu, 22 Sep 2005 22:51:46 +0100 --=-VYrzn/Iq890mDVByUuhY Content-Type: text/plain Content-Transfer-Encoding: 7bit Hi Marcel, On Thu, 2005-09-22 at 20:23 +0200, Marcel Holtmann wrote: > Hi Bastien, > > > David, Florent, Paul, I've copied you on this mail as the > > pilot-sync-devel list seems to be down ATM. Bluez-devel people, I know a > > few have been interested in Hotsync'ing over Bluetooth for Palm devices. > > > > This patch should apply to the current CVS HEAD of pilot-link. > > It adds configure checks for BlueZ (with the default being to turn on > > the Bluetooth support), and use the "bt:" port. > > > > How-to use it: > > 1) Make sure your Palm and computer are paired > > 2) Select your computer as the Hotsync (Bluetooth->Setup > > devices->Hotsync, ignore the instructions on screen, and go through the > > wizard) > > 3) launch your favourite Palm conduit with the "bt:" port, such as: > > pilot-xfer -p bt: -l > > 4) Enjoy > > > > There are a few kludges though: > > - Multiple HOTSYNC SDP records could get created, you can remove them by > > hand using sdptool. > > look at the pand daemon and see how they handle the SDP records. There > is no need to make them persistent. If the application dies, the records > are automatically removed by sdpd. Ha! I fixed the gnome-bluetooth OBEX code to keep the session opened as well. > > - We need to wait for the rfcomm device to be created, and then handled > > by the hotplug scripts before we can use it. Marcel probably knows how > > to do this better than I do. > > Don't create a TTY device. You can use the RFCOMM socket directly. And that removes wads of code as well, much cleaner. Thanks. > > You can use bt: to only allow a specific Palm to connect to > > your conduit. > > > > Comments welcome. Palm hackers, is "bluetooth:" being used, and if not, > > could we hijack it, and is the current code mergeable? > > Someone has to send me a Palm device with Bluetooth, so I can do more > testing. Do you have a Palm? A Bluetooth SDIO card for a Palm is considerably cheaper than a brand new Palm... Thanks for the advices, I've attached the new patch below. Cheers --- Bastien Nocera --=-VYrzn/Iq890mDVByUuhY Content-Disposition: attachment; filename=pilot-link-bluetooth2.patch Content-Type: text/x-patch; name=pilot-link-bluetooth2.patch; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Index: configure.ac =================================================================== RCS file: /cvs/pilot-link/pilot-link_src/configure.ac,v retrieving revision 1.36 diff -u -p -r1.36 configure.ac --- configure.ac 17 Aug 2005 15:12:26 -0000 1.36 +++ configure.ac 22 Sep 2005 21:46:03 -0000 @@ -335,6 +335,34 @@ AM_CONDITIONAL(WITH_FREEBSDUSB, test x$u AM_CONDITIONAL(WITH_DARWINUSB, test x$usb_type = xdarwin) AC_SUBST(usb_libs) +dnl ******************************************* +dnl Test if building Bluetooth Support on Linux +dnl ******************************************* +have_bluez=no +use_bluez=no +msg_bluez="no" + +PKG_CHECK_MODULES(BLUEZ, bluez, have_bluez=yes, have_bluez=no) + +AC_MSG_CHECKING([for BlueZ]) +AC_ARG_WITH(bluez, + AC_HELP_STRING([--with-bluez], + [Enable usage of BlueZ]),, + use_bluez=auto) +if test "x$use_bluez" != "xno"; then + if test "x$have_bluez" = xno && test "x$use_bluez" = xyes; then + AC_MSG_ERROR([BlueZ explicitly requested but no support found]) + fi + if test "x$have_bluez" = xyes; then + AC_DEFINE(HAVE_BLUEZ, 1, [Define if we have BlueZ support]) + AC_MSG_RESULT([enabled]) + msg_bluez="yes" + else + AC_MSG_RESULT([not found]) + fi +fi + +AM_CONDITIONAL(WITH_BLUEZ, test x$have_bluez = "xyes") dnl ********************************* dnl Check for popt (use internal if needed) @@ -810,6 +838,7 @@ AC_MSG_RESULT([ Build for host.......... : $host Extra Warnings.......... : $set_compile_warnings Direct USB support...... : $msg_usb + BlueZ support........... : $msg_bluez Thread-safe libpisock... : $msg_threads ElectricFence checks.... : $msg_efence CPPFLAGS................ : $CPPFLAGS Index: include/Makefile.am =================================================================== RCS file: /cvs/pilot-link/pilot-link_src/include/Makefile.am,v retrieving revision 1.24 diff -u -p -r1.24 Makefile.am --- include/Makefile.am 9 Jun 2005 13:42:47 -0000 1.24 +++ include/Makefile.am 22 Sep 2005 21:46:03 -0000 @@ -2,6 +2,7 @@ c_headers = \ pi-address.h \ pi-appinfo.h \ pi-args.h \ + pi-bluetooth.h \ pi-buffer.h \ pi-cmp.h \ pi-contact.h \ Index: libpisock/Makefile.am =================================================================== RCS file: /cvs/pilot-link/pilot-link_src/libpisock/Makefile.am,v retrieving revision 1.25 diff -u -p -r1.25 Makefile.am --- libpisock/Makefile.am 26 Apr 2005 17:44:31 -0000 1.25 +++ libpisock/Makefile.am 22 Sep 2005 21:46:04 -0000 @@ -13,6 +13,8 @@ usb_FILES = \ freebsdusb.c \ darwinusb.c +bluez_FILES = bluetooth.c + if WITH_LIBUSB usb_SOURCE = usb.c libusb.c endif @@ -28,11 +30,16 @@ if WITH_DARWINUSB usb_SOURCE = usb.c darwinusb.c endif +if WITH_BLUEZ +bluez_SOURCE = bluetooth.c +endif + lib_LTLIBRARIES = libpisock.la libpisock_la_SOURCES = \ $(serial_SOURCE)\ $(usb_SOURCE) \ + $(bluez_SOURCE) \ address.c \ appinfo.c \ connect.c \ @@ -68,10 +75,10 @@ libpisock_la_SOURCES = \ # Including PTHREAD_CFLAGS here is a dirty ugly kluge. It works. libpisock_la_LIBADD = \ - @usb_libs@ @PTHREAD_LIBS@ @PTHREAD_CFLAGS@ + @usb_libs@ @PTHREAD_LIBS@ @PTHREAD_CFLAGS@ $(BLUEZ_LIBS) libpisock_la_LDFLAGS = \ -export-dynamic -version-info $(PISOCK_CURRENT):$(PISOCK_REVISION):$(PISOCK_AGE) -libpisock_la_CFLAGS = $(PIC_LIBS) @PTHREAD_CFLAGS@ +libpisock_la_CFLAGS = $(PIC_LIBS) $(BLUEZ_CFLAGS) @PTHREAD_CFLAGS@ -EXTRA_DIST = $(serial_FILES) $(usb_FILES) +EXTRA_DIST = $(serial_FILES) $(usb_FILES) $(bluez_FILES) Index: libpisock/socket.c =================================================================== RCS file: /cvs/pilot-link/pilot-link_src/libpisock/socket.c,v retrieving revision 1.104 diff -u -p -r1.104 socket.c --- libpisock/socket.c 20 Jul 2005 10:13:40 -0000 1.104 +++ libpisock/socket.c 22 Sep 2005 21:46:05 -0000 @@ -44,6 +44,9 @@ #ifdef HAVE_USB #include "pi-usb.h" #endif +#ifdef HAVE_BLUEZ +#include "pi-bluetooth.h" +#endif #include "pi-inet.h" #include "pi-slp.h" #include "pi-sys.h" @@ -1014,6 +1017,9 @@ pi_devsocket(int pi_sd, const char *port } else if (!strncmp (port, "net:", 4)) { strncpy(addr->pi_device, port + 4, sizeof(addr->pi_device)); ps->device = pi_inet_device (PI_NET_DEV); + } else if (!strncmp (port, "bt:", 3)) { + strncpy(addr->pi_device, port + 3, sizeof(addr->pi_device)); + ps->device = pi_bluetooth_device (PI_BLUETOOTH_DEV); } else if (!strncmp (port, "bluetooth:", 10)) { /* warning: this code is not well tested */ strncpy(addr->pi_device, port + 10, sizeof(addr->pi_device)); --- /dev/null 2005-07-22 22:09:04.821703896 +0100 +++ include/pi-bluetooth.h 2005-09-22 22:32:43.000000000 +0100 @@ -0,0 +1,70 @@ +/* + * pi-bluetooth.h + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + */ +#ifndef _PILOT_BLUETOOTH_H_ +#define _PILOT_BLUETOOTH_H_ + +#include "pi-args.h" +#include "pi-buffer.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PI_BLUETOOTH_DEV 1 + + struct pi_bluetooth_impl { + int (*open) PI_ARGS((pi_socket_t *ps, + struct pi_sockaddr *addr, size_t addrlen)); + int (*close) PI_ARGS((pi_socket_t *ps)); + int (*changebaud) PI_ARGS((pi_socket_t *ps)); + ssize_t (*write) PI_ARGS((pi_socket_t *ps, + PI_CONST unsigned char *buf, size_t len, int flags)); + ssize_t (*read) PI_ARGS((pi_socket_t *ps, + pi_buffer_t *buf, size_t expect, int flags)); + int (*flush) PI_ARGS((pi_socket_t *ps, int flags)); + int (*poll) PI_ARGS((pi_socket_t *ps, int timeout)); + }; + + struct pi_bluetooth_data { + struct pi_bluetooth_impl impl; + + /* Device name passed from the front-ends */ + char *device; + + /* Which channel we're listening on, the handle + * for the SDP record as well as the SDP session */ + int channel; + uint32_t handle; + sdp_session_t *sess; + + /* Time out */ + int timeout; + }; + + extern pi_device_t *pi_bluetooth_device + PI_ARGS((int type)); + + extern void pi_bluetooth_impl_init + PI_ARGS((struct pi_bluetooth_impl *impl)); + +#ifdef __cplusplus +} +#endif +#endif --- /dev/null 2005-07-22 22:09:04.821703896 +0100 +++ libpisock/bluetooth.c 2005-09-22 22:45:00.000000000 +0100 @@ -0,0 +1,856 @@ +/* + * bluetooth.c: Interface layer to serial HotSync connections + * + * Copyright (c) 1996, 1997, D. Jeff Dionne & Kenneth Albanowski + * Copyright (c) 1999, Tilo Christ + * Copyright (c) 2005, Florent Pillet + * Copyright (c) 2004, Paul Evans + * Copyright (c) 2005, Bastien Nocera + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library + * General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include +#include /* Needed for Redhat 6.x machines */ + +#include +#include +#include +#include +#include +#include + +#include "pi-debug.h" +#include "pi-source.h" +#include "pi-socket.h" +#include "pi-bluetooth.h" +#include "pi-cmp.h" +#include "pi-net.h" +#include "pi-error.h" +#include "pi-serial.h" +#include "pi-util.h" + +#ifdef OS2 +#include +#endif + +/* Declare prototypes */ +static int pi_bluetooth_open(struct pi_socket *ps, struct pi_sockaddr *addr, + int addrlen); +static int pi_bluetooth_connect(pi_socket_t *ps, struct sockaddr *addr, + size_t addrlen); +static int pi_bluetooth_bind(pi_socket_t *ps, struct sockaddr *addr, + size_t addrlen); +static int pi_bluetooth_listen(pi_socket_t *ps, int backlog); +static int pi_bluetooth_accept(pi_socket_t *ps, struct sockaddr *addr, + size_t *addrlen); +static int pi_bluetooth_getsockopt(pi_socket_t *ps, int level, + int option_name, void *option_value, + size_t *option_len); +static int pi_bluetooth_setsockopt(pi_socket_t *ps, int level, + int option_name, const void *option_value, + size_t *option_len); +static int pi_bluetooth_close(pi_socket_t *ps); +static int pi_bluetooth_flush(pi_socket_t *ps, int flags); +static ssize_t pi_bluetooth_write(struct pi_socket *ps, + const unsigned char *buf, size_t len, int flags); +static ssize_t pi_bluetooth_read(struct pi_socket *ps, + pi_buffer_t *buf, size_t len, int flags); + +extern int pi_socket_init(pi_socket_t *ps); + +/* SDP Helper functions */ +/* + * Copyright (C) 2004 Edd Dumbill + * Copyright (C) 2005 Bastien Nocera + * Mostly borrowed from BlueZ + * + * Copyright (C) 2001-2002 Nokia Corporation + * Copyright (C) 2002-2003 Maxim Krasnyansky + * Copyright (C) 2002-2005 Marcel Holtmann + * Copyright (C) 2002-2003 Stephen Crane + * Copyright (C) 2002-2003 Jean Tourrilhes + * + */ +#include +#include + +typedef struct { + char *name; + char *provider; + char *desc; + + unsigned int class; + unsigned int profile; + unsigned int channel; +} svc_info_t; + +#define HOTSYNC_CHANNEL 22 + +static unsigned char hotsync_uuid[] = { 0xD8, 0x0C, 0xF9, 0xEA, 0x13, 0x4C, 0x11, 0xD5, + 0x83, 0xCE, 0x00, 0x30, 0x65, 0x7C, 0x54, 0x3C }; + +static int +add_hotsync(sdp_session_t *session, + sdp_record_t *rec, + bdaddr_t *interface, + svc_info_t *si, + uint32_t *handle, + int *channel_ret) +{ + sdp_record_t record; + sdp_list_t *root, *svclass, *proto; + uuid_t root_uuid, svclass_uuid, l2cap_uuid, rfcomm_uuid; + uint8_t channel = HOTSYNC_CHANNEL; + + memset(&record, 0, sizeof(record)); + record.handle = 0xffffffff; + + sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); + root = sdp_list_append(NULL, &root_uuid); + sdp_set_browse_groups(&record, root); + + sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); + proto = sdp_list_append(NULL, sdp_list_append(NULL, &l2cap_uuid)); + + sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); + proto = sdp_list_append(proto, sdp_list_append( + sdp_list_append(NULL, &rfcomm_uuid), sdp_data_alloc(SDP_UINT8, &channel))); + + sdp_set_access_protos(&record, sdp_list_append(NULL, proto)); + + sdp_uuid128_create(&svclass_uuid, (void *) hotsync_uuid); + svclass = sdp_list_append(NULL, &svclass_uuid); + sdp_set_service_classes(&record, svclass); + + sdp_set_info_attr(&record, "PalmOS HotSync", NULL, NULL); + + if (sdp_device_record_register(session, interface, &record, 0) < 0) { + fprintf(stderr, "Service Record registration failed\n"); + return -1; + } + + *handle = record.handle; + *channel_ret = HOTSYNC_CHANNEL; + return 0; +} + +static int +register_sdp (uint32_t *handle, int *channel, sdp_session_t *sess) +{ + svc_info_t si; + int ret; + bdaddr_t interface; + + bacpy (&interface, BDADDR_ANY); + sess = sdp_connect (&interface, BDADDR_LOCAL, 0); + + if (!sess) + return -1; + memset (&si, 0, sizeof(si)); + si.name = "HOTSYNC"; + ret = add_hotsync (sess, 0, &interface, &si, handle, channel); + + return ret; +} + +static int +deregister_sdp(uint32_t handle, sdp_session_t *sess) +{ + uint32_t range = 0x0000ffff; + sdp_list_t *attr; + sdp_record_t *rec; + bdaddr_t interface; + + if (!sess) { + return 0; + } + + bacpy(&interface, BDADDR_ANY); + + attr = sdp_list_append(0, &range); + rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attr); + sdp_list_free(attr, 0); + if (!rec) { + /* printf("Service Record not found.\n"); */ + sdp_close(sess); + return -1; + } + if (sdp_record_unregister(sess, rec)) { + fprintf (stderr, "Failed to unregister service record: %s\n", strerror(errno)); + sdp_close(sess); + return -1; + } + /* printf("Service Record deleted.\n"); */ + sdp_close(sess); + return 0; +} + +/* Protocol Functions */ +/*********************************************************************** + * + * Function: pi_bluetooth_protocol_dup + * + * Summary: clones an existing pi_protocol struct + * + * Parameters: pi_protocol* + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +static pi_protocol_t* +pi_bluetooth_protocol_dup (pi_protocol_t *prot) +{ + pi_protocol_t *new_prot; + + ASSERT (prot != NULL); + + new_prot = (pi_protocol_t *) malloc(sizeof (pi_protocol_t)); + + if (new_prot != NULL) { + new_prot->level = prot->level; + new_prot->dup = prot->dup; + new_prot->free = prot->free; + new_prot->read = prot->read; + new_prot->write = prot->write; + new_prot->flush = prot->flush; + new_prot->getsockopt = prot->getsockopt; + new_prot->setsockopt = prot->setsockopt; + new_prot->data = NULL; + } + + return new_prot; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_protocol_free + * + * Summary: frees an existing pi_protocol struct + * + * Parameters: pi_protocol* + * + * Returns: void + * + ***********************************************************************/ +static void +pi_bluetooth_protocol_free (pi_protocol_t *prot) +{ + ASSERT (prot != NULL); + + if (prot != NULL) + free(prot); +} + +/*********************************************************************** + * + * Function: pi_bluetooth_protocol + * + * Summary: creates and inits pi_protocol struct instance + * + * Parameters: pi_device_t* + * + * Returns: pi_protocol_t* or NULL if operation failed + * + ***********************************************************************/ +static pi_protocol_t* +pi_bluetooth_protocol (pi_device_t *dev) +{ + pi_protocol_t *prot; + struct pi_bluetooth_data *data; + + ASSERT (dev != NULL); + + prot = (pi_protocol_t *) malloc(sizeof (pi_protocol_t)); + + data = (struct pi_bluetooth_data *)(dev->data); + + if (prot != NULL) { + prot->level = PI_LEVEL_DEV; + prot->dup = pi_bluetooth_protocol_dup; + prot->free = pi_bluetooth_protocol_free; + prot->read = pi_bluetooth_read; + prot->write = pi_bluetooth_write; + prot->flush = pi_bluetooth_flush; + prot->getsockopt = pi_bluetooth_getsockopt; + prot->setsockopt = pi_bluetooth_setsockopt; + prot->data = NULL; + } + + return prot; +} + +/* Device Functions */ +/*********************************************************************** + * + * Function: pi_bluetooth_register_hotsync_sdp + * + * Summary: Gets on which channel the HOTSYNC service is, and + * registers it if necessary + * + * Parameters: None + * + * Returns: Nothing + * + **********************************************************************/ +static void +pi_bluetooth_register_hotsync_sdp (struct pi_bluetooth_data *data) +{ + if (register_sdp (&data->handle, &data->channel, data->sess) < 0) { + data->channel = -1; + data->handle = 0; + data->sess = NULL; + } +} + +/*********************************************************************** + * + * Function: pi_bluetooth_unregister_hotsync_sdp + * + * Summary: Removes the HOTSYNC service + * + * Parameters: None + * + * Returns: Nothing + * + **********************************************************************/ +static void +pi_bluetooth_unregister_hotsync_sdp (struct pi_bluetooth_data *data) +{ + if (data->handle != 0) + deregister_sdp (data->handle, data->sess); +} + +/*********************************************************************** + * + * Function: pi_bluetooth_device_free + * + * Summary: frees an existing pi_device struct + * + * Parameters: pi_device_t* + * + * Returns: void + * + ***********************************************************************/ +static void +pi_bluetooth_device_free (pi_device_t *dev) +{ + struct pi_bluetooth_data *data; + + ASSERT (dev != NULL); + + if (dev->data) { + data = dev->data; + pi_bluetooth_unregister_hotsync_sdp (data); + if (data->device) + free (data->device); + free(dev->data); + } + free(dev); +} + +/*********************************************************************** + * + * Function: pi_bluetooth_open + * + * Summary: Open a new BlueTooth RFCOMM socket + * + * Parameters: None + * + * Returns: A negative number on error, 0 otherwise + * + **********************************************************************/ +static int +pi_bluetooth_open(struct pi_socket *ps, struct pi_sockaddr *addr, int addrlen) +{ + int fd, flags; + struct pi_bluetooth_data *data = ps->device->data; + + pi_bluetooth_register_hotsync_sdp (data); + /* If we didn't manage to create an SDP record, force channel 22 and try + * again */ + if (data->channel < 0) { + fprintf (stderr, "didn't manage to get a channel\n"); + data->channel = 22; + } + + if ((fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) + return -1; + + if ((flags = fcntl(fd, F_GETFL, 0)) != -1) { + flags &= ~O_NONBLOCK; + fcntl(fd, F_SETFL, flags); + } + + if (pi_socket_setsd(ps, fd) < 0) + return -1; + + return 0; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_device + * + * Summary: creates and inits pi_device struct instance + * + * Parameters: device type + * + * Returns: pi_device_t* or NULL if operation failed + * + ***********************************************************************/ +pi_device_t* +pi_bluetooth_device (int type) +{ + pi_device_t *dev; + struct pi_bluetooth_data *data; + + dev = (pi_device_t *) malloc(sizeof (pi_device_t)); + if (dev == NULL) + return NULL; + + data = (struct pi_bluetooth_data *) malloc(sizeof (struct pi_bluetooth_data)); + if (data == NULL) { + free(dev); + return NULL; + } + + dev->free = pi_bluetooth_device_free; + dev->protocol = pi_bluetooth_protocol; + dev->bind = pi_bluetooth_bind; + dev->listen = pi_bluetooth_listen; + dev->accept = pi_bluetooth_accept; + dev->connect = pi_bluetooth_connect; + dev->close = pi_bluetooth_close; + + data->timeout = 0; + dev->data = data; + + return dev; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_connect + * + * Summary: Connect socket to a given address + * + * Parameters: pi_socket*, sockaddr*, size_t + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +static int +pi_bluetooth_connect(pi_socket_t *ps, struct sockaddr *addr, + size_t addrlen) +{ + ps->raddr = malloc(addrlen); + memcpy(ps->raddr, addr, addrlen); + ps->raddrlen = addrlen; + ps->laddr = malloc(addrlen); + memcpy(ps->laddr, addr, addrlen); + ps->laddrlen = addrlen; + + if (ps->type == PI_SOCK_STREAM) { + switch (ps->cmd) { + case PI_CMD_CMP: + if (cmp_tx_handshake(ps) < 0) + goto fail; + + break; + + case PI_CMD_NET: + break; + + case PI_CMD_SYS: + break; + } + } + ps->state = PI_SOCK_CONN_INIT; + ps->command = 0; + + return 0; + +fail: + pi_close (ps->sd); + return -1; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_bind + * + * Summary: Bind address to a local socket + * + * Parameters: pi_socket*, sockaddr*, size_t + * + * Returns: A negative number on error, 0 otherwise + * + ***********************************************************************/ +static int +pi_bluetooth_bind(pi_socket_t *ps, struct sockaddr *addr, size_t addrlen) +{ + struct pi_sockaddr *pa = (struct pi_sockaddr *) addr; + struct pi_bluetooth_data *data = + (struct pi_bluetooth_data *)ps->device->data; + char *device = pa->pi_device; + struct sockaddr_rc bindaddr; + + if (pi_bluetooth_open(ps, pa, addrlen) == -1) + return -1; /* errno already set */ + + data->device = strdup (device); + + bindaddr.rc_family = AF_BLUETOOTH; + bacpy(&bindaddr.rc_bdaddr, BDADDR_ANY); + bindaddr.rc_channel = data->channel; + + if (bind(ps->sd, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) { + pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + return -1; + } + + ps->laddr = malloc(addrlen); + memcpy(ps->laddr, addr, addrlen); + ps->laddrlen = addrlen; + + return 0; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_listen + * + * Summary: Prepare for incoming connections + * + * Parameters: pi_socket*, backlog + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int pi_bluetooth_listen(pi_socket_t *ps, int backlog) +{ + int result; + + listen(ps->sd, 10); + ps->state = PI_SOCK_LISTEN; + + return result; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_accept_rfcomm + * + * Summary: Accept an incoming connection and associate it with an + * RFCOMM serial device + * + * Parameters: None + * + * Returns: Nothing + * + ***********************************************************************/ +static int +pi_bluetooth_accept_rfcomm(struct pi_socket *ps, const char *device, struct sockaddr_rc *peeraddr, unsigned int *peeraddrlen) +{ + int rfcommfd; + + rfcommfd = accept(ps->sd, (struct sockaddr *)peeraddr, peeraddrlen); + if (rfcommfd < 0) { + pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + return -1; + } + + /* Check whether we need to really accept this connection */ + if (device[0] != '\0' && strcmp (device, "any") != 0) { + bdaddr_t tmp; + if (str2ba (device, &tmp) < 0) { + close (rfcommfd); + return -1; + } + if (bacmp (&tmp, &(peeraddr->rc_bdaddr)) != 0) { + close (rfcommfd); + return -1; + } + } + + return rfcommfd; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_accept + * + * Summary: Accept an incoming connection + * + * Parameters: pi_socket*, sockaddr* + * + * Returns: Nothing + * + ***********************************************************************/ +static int +pi_bluetooth_accept(pi_socket_t *ps, struct sockaddr *addr, + size_t *addrlen) +{ + struct pi_bluetooth_data *data = + (struct pi_bluetooth_data *)ps->device->data; + struct sockaddr_rc peeraddr; + unsigned int peeraddrlen = sizeof(peeraddr); + int sd; + + /* Wait for data */ + sd = pi_bluetooth_accept_rfcomm(ps, data->device, &peeraddr, &peeraddrlen); + if (sd < 0) { + pi_set_error(ps->sd, PI_ERR_GENERIC_SYSTEM); + goto fail; + } + + if (pi_socket_setsd(ps, sd) < 0) + return -1; + pi_socket_init(ps); + + if (ps->type == PI_SOCK_STREAM) { + switch (ps->cmd) { + case PI_CMD_CMP: + if (cmp_rx_handshake(ps, 0, 0) < 0) + return -1; + + break; + case PI_CMD_NET: + if (net_rx_handshake(ps) < 0) + return -1; + break; + } + + ps->dlprecord = 0; + } + + data->timeout = 0; + ps->command = 0; + ps->state = PI_SOCK_CONN_ACCEPT; + + return ps->sd; + +fail: + return -1; +} + +static int +pi_bluetooth_flush(pi_socket_t *ps, int flags) +{ + char buf[256]; + int fl; + + if (flags & PI_FLUSH_INPUT) { + if ((fl = fcntl(ps->sd, F_GETFL, 0)) != -1) { + fcntl(ps->sd, F_SETFL, fl | O_NONBLOCK); + while (read(ps->sd, buf, sizeof(buf)) > 0) + ; + fcntl(ps->sd, F_SETFL, fl); + } + } + return 0; +} + +static ssize_t +pi_bluetooth_read(struct pi_socket *ps, pi_buffer_t *buf, size_t len, int flags) +{ + int rbuf; + struct pi_bluetooth_data *data = (struct pi_bluetooth_data *)ps->device->data; + struct timeval t; + fd_set ready; + + if (pi_buffer_expect (buf, len) == NULL) { + return pi_set_error(ps->sd, PI_ERR_GENERIC_MEMORY); + } + + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + + /* If timeout == 0, wait forever for packet, otherwise wait till + timeout milliseconds */ + if (data->timeout == 0) + select(ps->sd + 1, &ready, 0, 0, 0); + else { + t.tv_sec = data->timeout / 1000; + t.tv_usec = (data->timeout % 1000) * 1000; + select(ps->sd + 1, &ready, 0, 0, &t); + } + /* If data is available in time, read it */ + if (FD_ISSET(ps->sd, &ready)) { + if (flags == PI_MSG_PEEK && len > 256) + len = 256; + rbuf = read(ps->sd, buf->data + buf->used, len); + } else { + LOG((PI_DBG_DEV, PI_DBG_LVL_WARN, "DEV RX BlueTooth timeout\n")); + pi_set_error(ps->sd, PI_ERR_SOCK_TIMEOUT); + return -1; + } + buf->used += rbuf; + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, "DEV RX BlueTooth Bytes: %d\n", rbuf)); + + return rbuf; +} + +static ssize_t +pi_bluetooth_write(struct pi_socket *ps, const unsigned char *buf, size_t len, int flags) +{ + int total, + nwrote; + struct pi_bluetooth_data *data = (struct pi_bluetooth_data *)ps->device->data; + struct timeval t; + fd_set ready; + + FD_ZERO(&ready); + FD_SET(ps->sd, &ready); + + total = len; + while (total > 0) { + if (data->timeout == 0) + select(ps->sd + 1, 0, &ready, 0, 0); + else { + t.tv_sec = data->timeout / 1000; + t.tv_usec = (data->timeout % 1000) * 1000; + select(ps->sd + 1, 0, &ready, 0, &t); + } + if (!FD_ISSET(ps->sd, &ready)) { + pi_set_error(ps->sd, PI_ERR_SOCK_IO); + return -1; + } + nwrote = write(ps->sd, buf, len); + if (nwrote < 0) { + pi_set_error(ps->sd, PI_ERR_SOCK_IO); + return -1; + } + total -= nwrote; + } + + LOG((PI_DBG_DEV, PI_DBG_LVL_INFO, "DEV TX BlueTooth Bytes: %d\n", len)); + return len; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_getsockopt + * + * Summary: get options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +pi_bluetooth_getsockopt(pi_socket_t *ps, int level, int option_name, + void *option_value, size_t *option_len) +{ + struct pi_bluetooth_data *data = + (struct pi_bluetooth_data *)ps->device->data; + + switch (option_name) { + case PI_DEV_TIMEOUT: + if (*option_len < sizeof (data->timeout)) + goto error; + memcpy (option_value, &data->timeout, + sizeof (data->timeout)); + *option_len = sizeof (data->timeout); + break; + } + + return 0; +error: + pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); + return -1; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_setsockopt + * + * Summary: set options on socket + * + * Parameters: pi_socket*, level, option name, option value, option length + * + * Returns: 0 for success, negative otherwise + * + ***********************************************************************/ +static int +pi_bluetooth_setsockopt(pi_socket_t *ps, int level, int option_name, + const void *option_value, size_t *option_len) +{ + struct pi_bluetooth_data *data = + (struct pi_bluetooth_data *)ps->device->data; + + switch (option_name) { + case PI_DEV_TIMEOUT: + if (*option_len != sizeof (data->timeout)) + goto error; + memcpy (&data->timeout, option_value, + sizeof (data->timeout)); + break; + } + + return 0; + +error: + pi_set_error(ps->sd, PI_ERR_GENERIC_ARGUMENT); + return -1; +} + +/*********************************************************************** + * + * Function: pi_bluetooth_close + * + * Summary: Close a connection, destroy the socket + * + * Parameters: pi_socket* + * + * Returns: always 0 for success + * + ***********************************************************************/ +static int pi_bluetooth_close(pi_socket_t *ps) +{ + if (ps->laddr) { + free(ps->laddr); + ps->laddr = NULL; + } + + if (ps->raddr) { + free(ps->raddr); + ps->raddr = NULL; + } + + return 0; +} + +/* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ +/* Local Variables: */ +/* indent-tabs-mode: t */ +/* c-basic-offset: 8 */ +/* End: */ --=-VYrzn/Iq890mDVByUuhY-- ------------------------------------------------------- SF.Net email is sponsored by: Tame your development challenges with Apache's Geronimo App Server. Download it for free - -and be entered to win a 42" plasma tv or your very own Sony(tm)PSP. Click here to play: http://sourceforge.net/geronimo.php _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel