Linux bluetooth development
 help / color / mirror / Atom feed
From: Bastien Nocera <hadess@hadess.net>
To: bluez-devel@lists.sourceforge.net
Cc: leonerd@leonerd.org.uk, hacker@gnu-designs.com, fpillet@mac.com
Subject: Re: [Bluez-devel] [PATCH] Palm Hotsync over Bluetooth
Date: Thu, 22 Sep 2005 22:51:46 +0100	[thread overview]
Message-ID: <1127425906.24352.20.camel@wyatt.hadess.net> (raw)
In-Reply-To: <1127413417.12287.19.camel@blade>

[-- Attachment #1: Type: text/plain, Size: 2098 bytes --]

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:<Palm bdaddr> 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 <hadess@hadess.net> 


[-- Attachment #2: pilot-link-bluetooth2.patch --]
[-- Type: text/x-patch, Size: 29792 bytes --]

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 <bluetooth/sdp.h>
+
+#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 <leonerd@leonerd.org.uk>
+ * Copyright (c) 2005, Bastien Nocera <hadess@hadess.net>
+ *
+ * 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 <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>		/* Needed for Redhat 6.x machines */
+
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#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 <sys/select.h>
+#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 <edd@usefulinc.com>
+ *  Copyright (C) 2005  Bastien Nocera <hadess@hadess.net>
+ *  Mostly borrowed from BlueZ
+ *
+ *  Copyright (C) 2001-2002  Nokia Corporation
+ *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
+ *  Copyright (C) 2002-2005  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2002-2003  Stephen Crane <steve.crane@rococosoft.com>
+ *  Copyright (C) 2002-2003  Jean Tourrilhes <jt@hpl.hp.com>
+ *
+ */
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+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: */

      reply	other threads:[~2005-09-22 21:51 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-09-22 18:05 [Bluez-devel] [PATCH] Palm Hotsync over Bluetooth Bastien Nocera
2005-09-22 18:23 ` Marcel Holtmann
2005-09-22 21:51   ` Bastien Nocera [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1127425906.24352.20.camel@wyatt.hadess.net \
    --to=hadess@hadess.net \
    --cc=bluez-devel@lists.sourceforge.net \
    --cc=fpillet@mac.com \
    --cc=hacker@gnu-designs.com \
    --cc=leonerd@leonerd.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox