[Pkg-bluetooth-commits] r480 - in /bluez-utils/branches/upstream/current: ./ audio/ common/ cups/ daemon/ eglib/ hcid/ input/ network/ rfcomm/ sdpd/ serial/ test/ tools/
filippo at users.alioth.debian.org
filippo at users.alioth.debian.org
Wed Jul 4 13:37:58 UTC 2007
Author: filippo
Date: Wed Jul 4 13:37:57 2007
New Revision: 480
URL: http://svn.debian.org/wsvn/pkg-bluetooth/?sc=1&rev=480
Log:
[svn-upgrade] Integrating new upstream version, bluez-utils (3.12)
Added:
bluez-utils/branches/upstream/current/audio/audio.conf
bluez-utils/branches/upstream/current/audio/device.c
bluez-utils/branches/upstream/current/audio/device.h
bluez-utils/branches/upstream/current/audio/error.c
bluez-utils/branches/upstream/current/audio/error.h
bluez-utils/branches/upstream/current/audio/gateway.c
bluez-utils/branches/upstream/current/audio/gateway.h
bluez-utils/branches/upstream/current/audio/test-audio (with props)
bluez-utils/branches/upstream/current/audio/unix.c
bluez-utils/branches/upstream/current/audio/unix.h
bluez-utils/branches/upstream/current/daemon/test-database (with props)
bluez-utils/branches/upstream/current/daemon/test-manager (with props)
bluez-utils/branches/upstream/current/hcid/server.c
bluez-utils/branches/upstream/current/hcid/server.h
bluez-utils/branches/upstream/current/serial/error.c
bluez-utils/branches/upstream/current/serial/error.h
bluez-utils/branches/upstream/current/serial/port.c
bluez-utils/branches/upstream/current/serial/port.h
bluez-utils/branches/upstream/current/serial/storage.c
bluez-utils/branches/upstream/current/serial/storage.h
Modified:
bluez-utils/branches/upstream/current/ChangeLog
bluez-utils/branches/upstream/current/audio/Makefile.am
bluez-utils/branches/upstream/current/audio/Makefile.in
bluez-utils/branches/upstream/current/audio/audio-api.txt
bluez-utils/branches/upstream/current/audio/ctl_bluetooth.c
bluez-utils/branches/upstream/current/audio/headset.c
bluez-utils/branches/upstream/current/audio/headset.h
bluez-utils/branches/upstream/current/audio/ipc.h
bluez-utils/branches/upstream/current/audio/main.c
bluez-utils/branches/upstream/current/audio/manager.c
bluez-utils/branches/upstream/current/audio/manager.h
bluez-utils/branches/upstream/current/audio/pcm_bluetooth.c
bluez-utils/branches/upstream/current/common/dbus-helper.c
bluez-utils/branches/upstream/current/common/dbus.c
bluez-utils/branches/upstream/current/common/dbus.h
bluez-utils/branches/upstream/current/common/ppoll.h
bluez-utils/branches/upstream/current/common/sdp-expat.c
bluez-utils/branches/upstream/current/common/sdp-glib.c
bluez-utils/branches/upstream/current/common/sdp-xml.c
bluez-utils/branches/upstream/current/common/sdp-xml.h
bluez-utils/branches/upstream/current/configure
bluez-utils/branches/upstream/current/configure.in
bluez-utils/branches/upstream/current/cups/Makefile.am
bluez-utils/branches/upstream/current/cups/Makefile.in
bluez-utils/branches/upstream/current/cups/main.c
bluez-utils/branches/upstream/current/daemon/Makefile.am
bluez-utils/branches/upstream/current/daemon/Makefile.in
bluez-utils/branches/upstream/current/daemon/echo.c
bluez-utils/branches/upstream/current/eglib/gmain.c
bluez-utils/branches/upstream/current/eglib/gmain.h
bluez-utils/branches/upstream/current/hcid/Makefile.am
bluez-utils/branches/upstream/current/hcid/Makefile.in
bluez-utils/branches/upstream/current/hcid/dbus-adapter.c
bluez-utils/branches/upstream/current/hcid/dbus-adapter.h
bluez-utils/branches/upstream/current/hcid/dbus-api.txt
bluez-utils/branches/upstream/current/hcid/dbus-common.c
bluez-utils/branches/upstream/current/hcid/dbus-common.h
bluez-utils/branches/upstream/current/hcid/dbus-database.c
bluez-utils/branches/upstream/current/hcid/dbus-database.h
bluez-utils/branches/upstream/current/hcid/dbus-hci.c
bluez-utils/branches/upstream/current/hcid/dbus-hci.h
bluez-utils/branches/upstream/current/hcid/dbus-sdp.c
bluez-utils/branches/upstream/current/hcid/dbus-sdp.h
bluez-utils/branches/upstream/current/hcid/dbus-service.c
bluez-utils/branches/upstream/current/hcid/dbus-service.h
bluez-utils/branches/upstream/current/hcid/device.c
bluez-utils/branches/upstream/current/hcid/hcid.8
bluez-utils/branches/upstream/current/hcid/hcid.h
bluez-utils/branches/upstream/current/hcid/main.c
bluez-utils/branches/upstream/current/hcid/security.c
bluez-utils/branches/upstream/current/input/device.c
bluez-utils/branches/upstream/current/input/device.h
bluez-utils/branches/upstream/current/input/manager.c
bluez-utils/branches/upstream/current/input/server.c
bluez-utils/branches/upstream/current/input/storage.c
bluez-utils/branches/upstream/current/input/storage.h
bluez-utils/branches/upstream/current/network/connection.c
bluez-utils/branches/upstream/current/network/connection.h
bluez-utils/branches/upstream/current/network/manager.c
bluez-utils/branches/upstream/current/network/manager.h
bluez-utils/branches/upstream/current/network/network-api.txt
bluez-utils/branches/upstream/current/network/server.c
bluez-utils/branches/upstream/current/network/server.h
bluez-utils/branches/upstream/current/network/test-network
bluez-utils/branches/upstream/current/rfcomm/main.c
bluez-utils/branches/upstream/current/rfcomm/rfcomm.1
bluez-utils/branches/upstream/current/sdpd/main.c
bluez-utils/branches/upstream/current/sdpd/sdpd.8
bluez-utils/branches/upstream/current/sdpd/sdpd.h
bluez-utils/branches/upstream/current/sdpd/server.c
bluez-utils/branches/upstream/current/sdpd/service.c
bluez-utils/branches/upstream/current/serial/Makefile.am
bluez-utils/branches/upstream/current/serial/Makefile.in
bluez-utils/branches/upstream/current/serial/manager.c
bluez-utils/branches/upstream/current/serial/manager.h
bluez-utils/branches/upstream/current/serial/serial-api.txt
bluez-utils/branches/upstream/current/test/apitest
bluez-utils/branches/upstream/current/test/l2test.c
bluez-utils/branches/upstream/current/tools/csr.c
bluez-utils/branches/upstream/current/tools/hciattach.c
bluez-utils/branches/upstream/current/tools/hcitool.c
bluez-utils/branches/upstream/current/tools/sdptool.c
Modified: bluez-utils/branches/upstream/current/ChangeLog
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/ChangeLog?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/ChangeLog (original)
+++ bluez-utils/branches/upstream/current/ChangeLog Wed Jul 4 13:37:57 2007
@@ -1,3 +1,32 @@
+ver 3.12:
+ Add support for limited discovery mode.
+ Add support for setting of event mask.
+ Add GetRemoteServiceIdentifiers method.
+ Add skeleton for local D-Bus server.
+ Add headset gain control methods.
+ Fix various headset implementation issues.
+ Fix various serial port service issues.
+ Fix various input service issues.
+ Let CUPS plugin discover printers in range.
+ Improve the BCM2035 UART init routine.
+ Ignore connection events for non-ACL links.
+
+ Note:
+ This version needs at least bluez-libs-3.12
+
+ver 3.11:
+ Update API documentation.
+ Minimize SDP root records and browse groups.
+ Use same decoder for text and URL strings.
+ Fix SDP pattern extraction for XML.
+ Fix network connection persistent state.
+ Add network connection helper methods.
+ Add initial version of serial port support.
+ Add class of device tracking.
+
+ Note:
+ This version needs at least bluez-libs-3.11
+
ver 3.10.1:
Add option to disable installation of manual pages.
Fix input service encryption setup.
Modified: bluez-utils/branches/upstream/current/audio/Makefile.am
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/Makefile.am?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/Makefile.am (original)
+++ bluez-utils/branches/upstream/current/audio/Makefile.am Wed Jul 4 13:37:57 2007
@@ -10,7 +10,9 @@
service_PROGRAMS = bluetoothd-service-audio
-bluetoothd_service_audio_SOURCES = main.c manager.h manager.c headset.h headset.c ipc.h
+bluetoothd_service_audio_SOURCES = main.c \
+ manager.h manager.c headset.h headset.c ipc.h unix.h unix.c \
+ error.h error.c device.h device.c gateway.h gateway.c
bluetoothd_service_audio_LDADD = $(top_builddir)/common/libhelper.a \
@GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
@@ -34,6 +36,6 @@
INCLUDES = -I$(top_srcdir)/common
-EXTRA_DIST = audio.service audio-api.txt asound.conf
+EXTRA_DIST = audio.service audio.conf audio-api.txt test-audio asound.conf
MAINTAINERCLEANFILES = Makefile.in
Modified: bluez-utils/branches/upstream/current/audio/Makefile.in
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/Makefile.in?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/Makefile.in (original)
+++ bluez-utils/branches/upstream/current/audio/Makefile.in Wed Jul 4 13:37:57 2007
@@ -81,10 +81,13 @@
servicePROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(service_PROGRAMS)
am__bluetoothd_service_audio_SOURCES_DIST = main.c manager.h manager.c \
- headset.h headset.c ipc.h
+ headset.h headset.c ipc.h unix.h unix.c error.h error.c \
+ device.h device.c gateway.h gateway.c
@AUDIOSERVICE_TRUE at am_bluetoothd_service_audio_OBJECTS = \
@AUDIOSERVICE_TRUE@ main.$(OBJEXT) manager.$(OBJEXT) \
- at AUDIOSERVICE_TRUE@ headset.$(OBJEXT)
+ at AUDIOSERVICE_TRUE@ headset.$(OBJEXT) unix.$(OBJEXT) \
+ at AUDIOSERVICE_TRUE@ error.$(OBJEXT) device.$(OBJEXT) \
+ at AUDIOSERVICE_TRUE@ gateway.$(OBJEXT)
bluetoothd_service_audio_OBJECTS = \
$(am_bluetoothd_service_audio_OBJECTS)
@AUDIOSERVICE_TRUE at bluetoothd_service_audio_DEPENDENCIES = \
@@ -284,7 +287,10 @@
@AUDIOSERVICE_TRUE@@CONFIGFILES_TRUE at confdir = $(sysconfdir)/bluetooth
@AUDIOSERVICE_TRUE@@CONFIGFILES_TRUE at conf_DATA = audio.service
@AUDIOSERVICE_TRUE at servicedir = $(libdir)/bluetooth
- at AUDIOSERVICE_TRUE@bluetoothd_service_audio_SOURCES = main.c manager.h manager.c headset.h headset.c ipc.h
+ at AUDIOSERVICE_TRUE@bluetoothd_service_audio_SOURCES = main.c \
+ at AUDIOSERVICE_TRUE@ manager.h manager.c headset.h headset.c ipc.h unix.h unix.c \
+ at AUDIOSERVICE_TRUE@ error.h error.c device.h device.c gateway.h gateway.c
+
@AUDIOSERVICE_TRUE at bluetoothd_service_audio_LDADD = $(top_builddir)/common/libhelper.a \
@AUDIOSERVICE_TRUE@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
@@ -298,7 +304,7 @@
@ALSA_TRUE@@AUDIOSERVICE_TRUE at libasound_module_ctl_bluetooth_la_LIBADD = @ALSA_LIBS@
AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ @ALSA_CFLAGS@ @SBC_CFLAGS@
INCLUDES = -I$(top_srcdir)/common
-EXTRA_DIST = audio.service audio-api.txt asound.conf
+EXTRA_DIST = audio.service audio.conf audio-api.txt test-audio asound.conf
MAINTAINERCLEANFILES = Makefile.in
all: all-am
@@ -403,10 +409,14 @@
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ctl_bluetooth.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/device.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/error.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/gateway.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/headset.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/main.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/manager.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/pcm_bluetooth.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/unix.Po at am__quote@
.c.o:
@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
Modified: bluez-utils/branches/upstream/current/audio/audio-api.txt
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/audio-api.txt?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/audio-api.txt (original)
+++ bluez-utils/branches/upstream/current/audio/audio-api.txt Wed Jul 4 13:37:57 2007
@@ -2,25 +2,60 @@
***************************************
Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
-Copyright (C) 2005-2006 Johan Hedberg <johan.hedberg at nokia.com>
+Copyright (C) 2005-2007 Johan Hedberg <johan.hedberg at nokia.com>
Copyright (C) 2005-2006 Brad Midgley <bmidgley at xmission.com>
-Audio Manager hierarchy
-=======================
-
-Interface org.bluez.audio.Manager
+org.bluez.audio.Manager interface
+=================================
+
Object path /org/bluez/audio
-Methods array{string} ListHeadsets()
-
- Returns list of headset objects that
- are configured.
+Methods
+ string CreateDevice(string address, array{string} interfaces) [experimental]
+
+ Creates a new audio device object. If not yet done,
+ this method will perform a SDP query on the remote
+ device and return first when the query is complete,
+ so be sure to call this method asynchronously.
+
+ The return parameter is the object path of the newly
+ created object. The method will fail if the remote
+ device does not support all of the interfaces listed
+ in the interfaces parameter.
+
+ void RemoveDevice(string path) [experimental]
+
+ Removes a device from the device tree. If there are
+ any connections open to the device they will be closed.
+
+ array{string} ListDevices(array{string} interfaces) [experimental]
+
+ Retuns an array of strings indicating the object paths
+ of available devices which implement as a minimum the
+ interfaces given through the parameter.
+
+ string DefaultDevice()
+
+ Returns the object path for the default device.
+
+ void ChangeDefaultDevice(string path)
+
+ Changes the default device.
+
+ array{string} ListHeadsets()
+
+ Returns list of headset objects that are configured.
+
+ string FindDeviceByAddress(string address) [experimental]
+
+ Searches the list of available devices and returns the
+ object path of the first device which matchess address.
+ If no device is found returns a DoesNotExist error.
string DefaultHeadset()
- Returns the object path for the default
- headset device.
+ Returns the object path for the default headset device.
void ChangeDefaultHeadset(string path)
@@ -28,15 +63,24 @@
string CreateHeadset(string address)
- Create a new headset device and returns
- its object path on return.
+ Create a new headset device and returns its object path
+ on return.
void RemoveHeadset(string path)
Removes a headset object and all information
related to it.
-Signals void HeadsetCreated(string path)
+Signals
+ void DeviceCreated(string path) [experimental]
+
+ Sent when a new device object has been created.
+
+ void DeviceRemoved(string path) [experimental]
+
+ Sent when a device object has been removed.
+
+ void HeadsetCreated(string path)
Sent when a new headset object has been created.
@@ -49,11 +93,25 @@
Sent when the default headset has changed.
-Audio Headset hierarchy
-=======================
-
-Interface org.bluez.audio.Headset
-Object path /org/bluez/audio/headset*
+org.bluez.audio.Device interface
+================================
+
+Object path(s) /org/bluez/audio/device*
+
+Methods string GetAddress() [experimental]
+
+ Returns the Bluetooth address of the remote device.
+
+ array{string} GetConnectedInterfaces() [experimental]
+
+ Returns a string list of interfaces that are in a
+ connected state.
+
+
+org.bluez.audio.Headset interface
+=================================
+
+Object path(s) /org/bluez/audio/device*
Methods void Connect()
@@ -84,6 +142,24 @@
Returns true if an audio connection to the headset
is active.
+ uint16 GetSpeakerGain()
+
+ Returns the current speaker gain if available,
+ otherwise returns the error NotAvailable.
+
+ uint16 GetMicrophoneGain()
+
+ Returns the current microphone gain if available,
+ otherwise returns the error NotAvailable.
+
+ void SetSpeakerGain(uint16 gain)
+
+ Changes the current speaker gain if possible.
+
+ void SetMicrophoneGain(uint16 gain)
+
+ Changes the current speaker gain if possible.
+
Signals void AnswerRequested()
Sent when the answer button is pressed on the headset
@@ -111,3 +187,15 @@
void MicrophoneGainChanged(uint16 gain)
The microphone gain changed.
+
+
+org.bluez.audio.Source interface
+================================
+
+Object path(s) /org/bluez/audio/device*
+
+
+org.bluez.audio.Sink interface
+==============================
+
+Object path(s) /org/bluez/audio/device*
Added: bluez-utils/branches/upstream/current/audio/audio.conf
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/audio.conf?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/audio.conf (added)
+++ bluez-utils/branches/upstream/current/audio/audio.conf Wed Jul 4 13:37:57 2007
@@ -1,0 +1,27 @@
+# Configuration file for the audio service
+
+# This section contains options which are not specific to any
+# particular interface
+[General]
+
+# If we want to disable support for specific services
+# Defaults to supporting all implemented services
+#Disable=Control,Source
+
+# SCO routing. Either PCM or HCI (in which case audio is routed to/from ALSA)
+# Defaults to HCI
+SCORouting=PCM
+
+# Headset interface specific options (i.e. options which affect how the audio
+# service interacts with remote headset devices)
+[Headset]
+
+# Set to true to only support HSP
+# Defaults to false
+DisableHFP=true
+
+# Just an example of potential config options for the other interfaces
+#[Sink]
+#Codecs=SBC,MPEG12
+#SBCChannelMode=joint
+#SBCBitpool=51
Modified: bluez-utils/branches/upstream/current/audio/ctl_bluetooth.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/ctl_bluetooth.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/ctl_bluetooth.c (original)
+++ bluez-utils/branches/upstream/current/audio/ctl_bluetooth.c Wed Jul 4 13:37:57 2007
@@ -31,13 +31,13 @@
#include <alsa/asoundlib.h>
#include <alsa/control_external.h>
-#ifndef UNIX_PATH_MAX
-#define UNIX_PATH_MAX 108
+#include "ipc.h"
+
+#ifdef ENABLE_DEBUG
+#define DBG(fmt, arg...) printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
+#else
+#define DBG(fmt, arg...)
#endif
-
-#define DBG(fmt, arg...) printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
-
-#define SOCKET_NAME "/org/bluez/audio"
#define BLUETOOTH_MINVOL 0
#define BLUETOOTH_MAXVOL 15
@@ -57,15 +57,24 @@
[BLUETOOTH_CAPTURE] = "Capture volume",
};
+static void bluetooth_exit(struct bluetooth_data *data)
+{
+ if (data == NULL)
+ return;
+
+ if (data->sock >= 0)
+ close(data->sock);
+
+ free(data);
+}
+
static void bluetooth_close(snd_ctl_ext_t *ext)
{
struct bluetooth_data *data = ext->private_data;
DBG("ext %p", ext);
- close(data->sock);
-
- free(data);
+ bluetooth_exit(data);
}
static int bluetooth_elem_count(snd_ctl_ext_t *ext)
@@ -129,48 +138,140 @@
return 0;
}
+static int bluetooth_send_ctl(struct bluetooth_data *data,
+ struct ipc_packet *pkt, int len)
+{
+ int ret;
+
+ ret = send(data->sock, pkt, len, MSG_NOSIGNAL);
+ if (ret <= 0) {
+ SYSERR("Unable to request new volume value to server");
+ return -errno;
+ }
+
+ ret = recv(data->sock, pkt, len, 0);
+ if (ret <= 0) {
+ SYSERR("Unable to receive new volume value from server");
+ return -errno;
+ }
+
+ if(pkt->type != PKT_TYPE_CTL_RSP) {
+ SNDERR("Unexpected packet type %d received", pkt->type);
+ return -EINVAL;
+ }
+
+ if(pkt->length != sizeof(struct ipc_data_ctl)) {
+ SNDERR("Unexpected packet length %d received", pkt->length);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int bluetooth_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
long *value)
{
struct bluetooth_data *data = ext->private_data;
- unsigned char buf[] = { 0x00, 0x00 };
- int len;
+ struct ipc_packet *pkt;
+ struct ipc_data_ctl *ctl;
+ int len, ret;
DBG("ext %p key %ld", ext, key);
- len = write(data->sock, buf, sizeof(buf));
-
+ len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_ctl);
+ pkt = malloc(len);
+ memset(pkt, 0, len);
*value = 0;
- return 0;
+ pkt->type = PKT_TYPE_CTL_REQ;
+ pkt->length = sizeof(struct ipc_data_ctl);
+ ctl = (struct ipc_data_ctl *) pkt->data;
+ ctl->mode = key;
+
+ if ((ret = bluetooth_send_ctl(data, pkt, len)) < 0)
+ goto done;
+
+ *value = ctl->key;
+done:
+ free(pkt);
+ return ret;
}
static int bluetooth_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
long *value)
{
struct bluetooth_data *data = ext->private_data;
- unsigned char buf[] = { 0xff, 0xff };
- int len;
+ struct ipc_packet *pkt;
+ struct ipc_data_ctl *ctl;
+ long current;
+ int len, ret;
DBG("ext %p key %ld", ext, key);
- len = write(data->sock, buf, sizeof(buf));
-
- return 0;
+ if ((ret = bluetooth_read_integer(ext, key, ¤t)) < 0)
+ return ret;
+
+ if (*value == current)
+ return 0;
+
+ len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_ctl);
+ pkt = malloc(len);
+ memset(pkt, 0, len);
+
+ pkt->length = sizeof(struct ipc_data_ctl);
+ ctl = (struct ipc_data_ctl *) pkt->data;
+ ctl->mode = key;
+
+ while (*value != current) {
+ pkt->type = PKT_TYPE_CTL_REQ;
+ ctl->key = (*value > current) ? CTL_KEY_VOL_UP : CTL_KEY_VOL_DOWN;
+
+ if ((ret = bluetooth_send_ctl(data, pkt, len)) < 0)
+ break;
+
+ current = ctl->key;
+ }
+
+ free(pkt);
+ return ret;
}
static int bluetooth_read_event(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id,
unsigned int *event_mask)
{
struct bluetooth_data *data = ext->private_data;
- unsigned char buf[128];
- int len;
-
- //DBG("ext %p id %p", ext, id);
-
- len = recv(data->sock, buf, sizeof(buf), MSG_DONTWAIT);
-
- return 0;
+ struct ipc_packet *pkt;
+ struct ipc_data_ctl *ctl;
+ int len, ret;
+
+ DBG("ext %p id %p", ext, id);
+
+ len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_ctl);
+ pkt = malloc(len);
+ memset(pkt, 0, len);
+
+ ret = recv(data->sock, pkt, len, MSG_DONTWAIT);
+ if (ret <= 0)
+ return -errno;
+
+ if(pkt->type != PKT_TYPE_CTL_NTFY) {
+ SNDERR("Unexpected packet type %d received!", pkt->type);
+ return -EAGAIN;
+ }
+
+ if(pkt->length != sizeof(struct ipc_data_ctl)) {
+ SNDERR("Unexpected packet length %d received", pkt->length);
+ return -EAGAIN;
+ }
+
+ ctl = (struct ipc_data_ctl *) pkt->data;
+ snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
+ snd_ctl_elem_id_set_name(id, ctl->mode == BLUETOOTH_PLAYBACK ?
+ vol_devices[BLUETOOTH_PLAYBACK] :
+ vol_devices[BLUETOOTH_CAPTURE]);
+ *event_mask = SND_CTL_EVENT_MASK_VALUE;
+
+ return 1;
}
static snd_ctl_ext_callback_t bluetooth_callback = {
@@ -185,68 +286,60 @@
.read_event = bluetooth_read_event,
};
-SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth)
-{
- snd_config_iterator_t iter, next;
- struct bluetooth_data *data;
- struct sockaddr_un addr;
- unsigned int id;
- int sk, err;
-
- DBG("Bluetooth Control plugin");
-
- snd_config_for_each(iter, next, conf) {
- snd_config_t *n = snd_config_iterator_entry(iter);
- const char *id;
-
- if (snd_config_get_id(n, &id) < 0)
- continue;
-
- if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0)
- continue;
-
- SNDERR("Unknown field %s", id);
-
+static int bluetooth_init(struct bluetooth_data *data)
+{
+ int sk, err, id;
+ struct sockaddr_un addr = {
+ AF_UNIX, IPC_SOCKET_NAME
+ };
+
+ if (!data)
return -EINVAL;
- }
+
+ memset(data, 0, sizeof(struct bluetooth_data));
+
+ data->sock = -1;
id = abs(getpid() * rand());
- sk = socket(PF_LOCAL, SOCK_DGRAM, 0);
- if (sk < 0) {
+ if ((sk = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
+ err = -errno;
SNDERR("Can't open socket");
return -errno;
}
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s/%d", SOCKET_NAME, id);
-
- if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- SNDERR("Can't bind socket");
- close(sk);
- return -errno;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s", SOCKET_NAME);
-
+ DBG("Connecting to address: %s", addr.sun_path + 1);
if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ err = -errno;
SNDERR("Can't connect socket");
close(sk);
- return -errno;
- }
-
- data = malloc(sizeof(*data));
+ return err;
+ }
+
+ data->sock = sk;
+
+ return 0;
+}
+
+SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth)
+{
+ struct bluetooth_data *data;
+ int err;
+
+ DBG("Bluetooth Control plugin");
+
+ data = malloc(sizeof(struct bluetooth_data));
+ memset(data, 0, sizeof(struct bluetooth_data));
if (!data) {
- close(sk);
- return -ENOMEM;
- }
+ err = -ENOMEM;
+ goto error;
+ }
+
+ err = bluetooth_init(data);
+ if (err < 0)
+ goto error;
memset(data, 0, sizeof(*data));
-
- data->sock = sk;
data->ext.version = SND_CTL_EXT_VERSION;
data->ext.card_idx = -1;
@@ -258,7 +351,7 @@
strncpy(data->ext.mixername, "Bluetooth Audio", sizeof(data->ext.mixername) - 1);
data->ext.callback = &bluetooth_callback;
- data->ext.poll_fd = sk;
+ data->ext.poll_fd = data->sock;
data->ext.private_data = data;
err = snd_ctl_ext_create(&data->ext, name, mode);
@@ -270,9 +363,7 @@
return 0;
error:
- close(sk);
-
- free(data);
+ bluetooth_exit(data);
return err;
}
Added: bluez-utils/branches/upstream/current/audio/device.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/device.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/device.c (added)
+++ bluez-utils/branches/upstream/current/audio/device.c Wed Jul 4 13:37:57 2007
@@ -1,0 +1,238 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "dbus.h"
+#include "dbus-helper.h"
+#include "logging.h"
+#include "textfile.h"
+
+#include "device.h"
+
+static DBusHandlerResult device_get_address(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct device *device = data;
+ DBusMessage *reply;
+ char address[18], *ptr = address;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ ba2str(&device->dst, address);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &ptr,
+ DBUS_TYPE_INVALID);
+
+ return send_message_and_unref(conn, reply);
+}
+
+static DBusHandlerResult device_get_connected(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessageIter iter, array_iter;
+ struct device *device = data;
+ DBusMessage *reply;
+ const char *iface;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING,
+ &array_iter);
+
+ if (device->headset &&
+ headset_get_state(device) >= HEADSET_STATE_CONNECTED) {
+ iface = AUDIO_HEADSET_INTERFACE;
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_STRING, &iface);
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return send_message_and_unref(conn, reply);
+}
+
+static DBusMethodVTable device_methods[] = {
+ { "GetAddress", device_get_address, "", "s" },
+ { "GetConnectedInterfaces", device_get_connected, "", "s" },
+ { NULL, NULL, NULL, NULL }
+};
+
+static void device_free(struct device *device)
+{
+ if (device->headset)
+ headset_free(device);
+
+ if (device->conn)
+ dbus_connection_unref(device->conn);
+
+ if (device->adapter_path)
+ g_free(device->adapter_path);
+
+ if (device->path)
+ g_free(device->path);
+
+ g_free(device);
+}
+
+static void device_unregister(DBusConnection *conn, void *data)
+{
+ struct device *device = data;
+
+ info("Unregistered device path:%s", device->path);
+
+ device_free(device);
+}
+
+struct device *device_register(DBusConnection *conn,
+ const char *path, bdaddr_t *bda)
+{
+ struct device *device;
+ bdaddr_t src;
+ int dev_id;
+
+ if (!conn || !path)
+ return NULL;
+
+ bacpy(&src, BDADDR_ANY);
+ dev_id = hci_get_route(NULL);
+ if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0))
+ return NULL;
+
+ device = g_new0(struct device, 1);
+
+ if (!dbus_connection_create_object_path(conn, path, device,
+ device_unregister)) {
+ error("D-Bus failed to register %s path", path);
+ device_free(device);
+ return NULL;
+ }
+
+ if (!dbus_connection_register_interface(conn, path,
+ AUDIO_DEVICE_INTERFACE, device_methods, NULL, NULL)) {
+ error("Failed to register %s interface to %s",
+ AUDIO_DEVICE_INTERFACE, path);
+ dbus_connection_destroy_object_path(conn, path);
+ return NULL;
+ }
+
+ device->path = g_strdup(path);
+ bacpy(&device->dst, bda);
+ bacpy(&device->src, &src);
+ device->conn = dbus_connection_ref(conn);
+ device->adapter_path = g_malloc0(16);
+ snprintf(device->adapter_path, 16, "/org/bluez/hci%d", dev_id);
+
+ return device;
+}
+
+int device_store(struct device *device, gboolean is_default)
+{
+ char value[64];
+ char filename[PATH_MAX + 1];
+ char src_addr[18], dst_addr[18];
+
+ if (!device->path)
+ return -EINVAL;
+
+ ba2str(&device->dst, dst_addr);
+ ba2str(&device->src, src_addr);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "audio");
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ if (is_default)
+ textfile_put(filename, "default", dst_addr);
+ if (device->headset)
+ snprintf(value, 64, "headset");
+ else if (device->gateway)
+ snprintf(value, 64, "gateway");
+ else if (device->sink)
+ snprintf(value, 64, "sink");
+ else if (device->source)
+ snprintf(value, 64, "source");
+ else if (device->control)
+ snprintf(value, 64, "control");
+ else
+ snprintf(value, 64, "target");
+
+ return textfile_put(filename, dst_addr, value);
+}
+
+void device_finish_sdp_transaction(struct device *device)
+{
+ char address[18], *addr_ptr = address;
+ DBusMessage *msg, *reply;
+ DBusError derr;
+
+ ba2str(&device->dst, address);
+
+ msg = dbus_message_new_method_call("org.bluez", device->adapter_path,
+ "org.bluez.Adapter",
+ "FinishRemoteServiceTransaction");
+ if (!msg) {
+ error("Unable to allocate new method call");
+ return;
+ }
+
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr,
+ DBUS_TYPE_INVALID);
+
+ dbus_error_init(&derr);
+ reply = dbus_connection_send_with_reply_and_block(device->conn,
+ msg, -1, &derr);
+
+ dbus_message_unref(msg);
+
+ if (dbus_error_is_set(&derr) ||
+ dbus_set_error_from_message(&derr, reply)) {
+ error("FinishRemoteServiceTransaction(%s) failed: %s",
+ address, derr.message);
+ dbus_error_free(&derr);
+ return;
+ }
+
+ dbus_message_unref(reply);
+}
Added: bluez-utils/branches/upstream/current/audio/device.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/device.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/device.h (added)
+++ bluez-utils/branches/upstream/current/audio/device.h Wed Jul 4 13:37:57 2007
@@ -1,0 +1,78 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <bluetooth/bluetooth.h>
+
+#include "headset.h"
+#include "gateway.h"
+
+#define AUDIO_DEVICE_INTERFACE "org.bluez.audio.Device"
+
+#define GENERIC_AUDIO_UUID "00001203-0000-1000-8000-00805F9B34FB"
+
+#define HSP_HS_UUID "00001108-0000-1000-8000-00805F9B34FB"
+#define HSP_AG_UUID "00001112-0000-1000-8000-00805F9B34FB"
+
+#define HFP_HS_UUID "0000111E-0000-1000-8000-00805F9B34FB"
+#define HFP_AG_UUID "0000111F-0000-1000-8000-00805F9B34FB"
+
+#define ADVANCED_AUDIO_UUID "0000110D-0000-1000-8000-00805F9B34FB"
+
+#define A2DP_SOURCE_UUID "0000110A-0000-1000-8000-00805F9B34FB"
+#define A2DP_SINK_UUID "0000110B-0000-1000-8000-00805F9B34FB"
+
+#define AVRCP_REMOTE_UUID "0000110E-0000-1000-8000-00805F9B34FB"
+#define AVRCP_TARGET_UUID "0000110C-0000-1000-8000-00805F9B34FB"
+
+/* Move these to respective .h files once they exist */
+#define AUDIO_SINK_INTERFACE "org.bluez.audio.Sink"
+#define AUDIO_SOURCE_INTERFACE "org.bluez.audio.Source"
+#define AUDIO_CONTROL_INTERFACE "org.bluez.audio.Control"
+#define AUDIO_TARGET_INTERFACE "org.bluez.audio.Target"
+
+struct sink;
+struct source;
+struct control;
+struct target;
+
+struct device {
+ DBusConnection *conn;
+ char *adapter_path;
+ char *path;
+ bdaddr_t src;
+ bdaddr_t dst;
+
+ struct headset *headset;
+ struct gateway *gateway;
+ struct sink *sink;
+ struct source *source;
+ struct control *control;
+ struct target *target;
+};
+
+struct device *device_register(DBusConnection *conn,
+ const char *path, bdaddr_t *bda);
+
+int device_store(struct device *device, gboolean is_default);
+
+void device_finish_sdp_transaction(struct device *device);
Added: bluez-utils/branches/upstream/current/audio/error.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/error.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/error.c (added)
+++ bluez-utils/branches/upstream/current/audio/error.c Wed Jul 4 13:37:57 2007
@@ -1,0 +1,103 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "error.h"
+#include "logging.h"
+
+#define AUDIO_ERROR_INTERFACE "org.bluez.audio.Error"
+
+/* FIXME: Remove these once global error functions exist */
+static DBusHandlerResult error_reply(DBusConnection *conn, DBusMessage *msg,
+ const char *name, const char *descr)
+{
+ DBusMessage *derr;
+
+ if (!conn || !msg)
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+ derr = dbus_message_new_error(msg, name, descr);
+ if (!derr) {
+ error("Unable to allocate new error return");
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ return send_message_and_unref(conn, derr);
+}
+
+DBusHandlerResult err_invalid_args(DBusConnection *conn,
+ DBusMessage *msg, const char *descr)
+{
+ return error_reply(conn, msg,
+ AUDIO_ERROR_INTERFACE ".InvalidArguments",
+ descr ? descr : "Invalid arguments in method call");
+}
+
+DBusHandlerResult err_already_connected(DBusConnection *conn, DBusMessage *msg)
+{
+ return error_reply(conn, msg,
+ AUDIO_ERROR_INTERFACE ".AlreadyConnected",
+ "Already connected to a device");
+}
+
+DBusHandlerResult err_not_connected(DBusConnection *conn, DBusMessage *msg)
+{
+ return error_reply(conn, msg,
+ AUDIO_ERROR_INTERFACE ".NotConnected",
+ "Not connected to any device");
+}
+
+DBusHandlerResult err_not_supported(DBusConnection *conn, DBusMessage *msg)
+{
+ return error_reply(conn, msg,
+ AUDIO_ERROR_INTERFACE ".NotSupported",
+ "The service is not supported by the remote device");
+}
+
+DBusHandlerResult err_connect_failed(DBusConnection *conn,
+ DBusMessage *msg, const char *err)
+{
+ return error_reply(conn, msg,
+ AUDIO_ERROR_INTERFACE ".ConnectFailed", err);
+}
+
+DBusHandlerResult err_does_not_exist(DBusConnection *conn, DBusMessage *msg)
+{
+ return error_reply(conn, msg,
+ AUDIO_ERROR_INTERFACE ".DoesNotExist",
+ "Does not exist");
+}
+
+DBusHandlerResult err_not_available(DBusConnection *conn, DBusMessage *msg)
+{
+ return error_reply(conn, msg, ".NotAvailable", "Not available");
+}
+
+DBusHandlerResult err_failed(DBusConnection *conn,
+ DBusMessage *msg, const char *dsc)
+{
+ return error_reply(conn, msg, AUDIO_ERROR_INTERFACE ".Failed", dsc);
+}
Added: bluez-utils/branches/upstream/current/audio/error.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/error.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/error.h (added)
+++ bluez-utils/branches/upstream/current/audio/error.h Wed Jul 4 13:37:57 2007
@@ -1,0 +1,36 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "dbus.h"
+
+DBusHandlerResult err_invalid_args(DBusConnection *conn,
+ DBusMessage *msg, const char *descr);
+DBusHandlerResult err_already_connected(DBusConnection *conn, DBusMessage *msg);
+DBusHandlerResult err_not_connected(DBusConnection *conn, DBusMessage * msg);
+DBusHandlerResult err_not_supported(DBusConnection *conn, DBusMessage *msg);
+DBusHandlerResult err_connect_failed(DBusConnection *conn,
+ DBusMessage *msg, const char *err);
+DBusHandlerResult err_does_not_exist(DBusConnection *conn, DBusMessage *msg);
+DBusHandlerResult err_not_available(DBusConnection *conn, DBusMessage *msg);
+DBusHandlerResult err_failed(DBusConnection *conn,
+ DBusMessage *msg, const char *dsc);
Added: bluez-utils/branches/upstream/current/audio/gateway.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/gateway.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/gateway.c (added)
+++ bluez-utils/branches/upstream/current/audio/gateway.c Wed Jul 4 13:37:57 2007
@@ -1,0 +1,551 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+#include <glib.h>
+
+#include <dbus/dbus.h>
+
+#include "dbus.h"
+#include "dbus-helper.h"
+#include "logging.h"
+#include "manager.h"
+#include "error.h"
+
+static uint32_t hs_record_id = 0;
+static uint32_t hf_record_id = 0;
+
+static GIOChannel *hs_server = NULL;
+static GIOChannel *hf_server = NULL;
+
+static DBusConnection *connection = NULL;
+
+static int gateway_hsp_ag_record(sdp_buf_t *buf, uint8_t ch)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+ uuid_t l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ sdp_data_t *channel;
+ int ret;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
+ profile.version = 0x0100;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &ch);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "Headset Audio Gateway", 0, 0);
+
+ if (sdp_gen_record_pdu(&record, buf) < 0)
+ ret = -1;
+ else
+ ret = 0;
+
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(pfseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_list_free(root, 0);
+ sdp_list_free(svclass_id, 0);
+ sdp_list_free(record.attrlist, (sdp_free_func_t) sdp_data_free);
+ sdp_list_free(record.pattern, free);
+
+ return ret;
+}
+
+static int gateway_hfp_ag_record(sdp_buf_t *buf, uint8_t ch)
+{
+ sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+ uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
+ uuid_t l2cap_uuid, rfcomm_uuid;
+ sdp_profile_desc_t profile;
+ sdp_list_t *aproto, *proto[2];
+ sdp_record_t record;
+ uint16_t u16 = 0x0009;
+ sdp_data_t *channel, *features;
+ uint8_t netid = 0x01;
+ sdp_data_t *network = sdp_data_alloc(SDP_UINT8, &netid);
+ int ret;
+
+ memset(&record, 0, sizeof(sdp_record_t));
+
+ sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+ root = sdp_list_append(0, &root_uuid);
+ sdp_set_browse_groups(&record, root);
+
+ sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
+ svclass_id = sdp_list_append(0, &svclass_uuid);
+ sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
+ svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
+ sdp_set_service_classes(&record, svclass_id);
+
+ sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
+ profile.version = 0x0105;
+ pfseq = sdp_list_append(0, &profile);
+ sdp_set_profile_descs(&record, pfseq);
+
+ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+ proto[0] = sdp_list_append(0, &l2cap_uuid);
+ apseq = sdp_list_append(0, proto[0]);
+
+ sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+ proto[1] = sdp_list_append(0, &rfcomm_uuid);
+ channel = sdp_data_alloc(SDP_UINT8, &ch);
+ proto[1] = sdp_list_append(proto[1], channel);
+ apseq = sdp_list_append(apseq, proto[1]);
+
+ features = sdp_data_alloc(SDP_UINT16, &u16);
+ sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+ aproto = sdp_list_append(0, apseq);
+ sdp_set_access_protos(&record, aproto);
+
+ sdp_set_info_attr(&record, "Hands-Free Audio Gateway", 0, 0);
+
+ sdp_attr_add(&record, SDP_ATTR_EXTERNAL_NETWORK, network);
+
+ if (sdp_gen_record_pdu(&record, buf) < 0)
+ ret = -1;
+ else
+ ret = 0;
+
+ sdp_data_free(channel);
+ sdp_list_free(proto[0], 0);
+ sdp_list_free(proto[1], 0);
+ sdp_list_free(apseq, 0);
+ sdp_list_free(pfseq, 0);
+ sdp_list_free(aproto, 0);
+ sdp_list_free(root, 0);
+ sdp_list_free(svclass_id, 0);
+ sdp_list_free(record.attrlist, (sdp_free_func_t) sdp_data_free);
+ sdp_list_free(record.pattern, free);
+
+ return ret;
+}
+
+static uint32_t gateway_add_ag_record(uint8_t channel, sdp_buf_t *buf)
+{
+ DBusMessage *msg, *reply;
+ DBusError derr;
+ dbus_uint32_t rec_id;
+
+ msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+ "org.bluez.Database",
+ "AddServiceRecord");
+ if (!msg) {
+ error("Can't allocate new method call");
+ return 0;
+ }
+
+ dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &buf->data, buf->data_size,
+ DBUS_TYPE_INVALID);
+
+ dbus_error_init(&derr);
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ msg, -1, &derr);
+
+ dbus_message_unref(msg);
+
+ if (dbus_error_is_set(&derr) ||
+ dbus_set_error_from_message(&derr, reply)) {
+ error("Adding service record failed: %s", derr.message);
+ dbus_error_free(&derr);
+ return 0;
+ }
+
+ dbus_message_get_args(reply, &derr, DBUS_TYPE_UINT32, &rec_id,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_error_is_set(&derr)) {
+ error("Invalid arguments to AddServiceRecord reply: %s",
+ derr.message);
+ dbus_message_unref(reply);
+ dbus_error_free(&derr);
+ return 0;
+ }
+
+ dbus_message_unref(reply);
+
+ debug("add_ag_record: got record id 0x%x", rec_id);
+
+ return rec_id;
+}
+
+static int gateway_remove_ag_record(uint32_t rec_id)
+{
+ DBusMessage *msg, *reply;
+ DBusError derr;
+
+ msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+ "org.bluez.Database",
+ "RemoveServiceRecord");
+ if (!msg) {
+ error("Can't allocate new method call");
+ return 0;
+ }
+
+ dbus_message_append_args(msg, DBUS_TYPE_UINT32, &rec_id,
+ DBUS_TYPE_INVALID);
+
+ dbus_error_init(&derr);
+ reply = dbus_connection_send_with_reply_and_block(connection,
+ msg, -1, &derr);
+
+ dbus_message_unref(msg);
+
+ if (dbus_error_is_set(&derr)) {
+ error("Removing service record 0x%x failed: %s",
+ rec_id, derr.message);
+ dbus_error_free(&derr);
+ return 0;
+ }
+
+ dbus_message_unref(reply);
+
+ return 0;
+}
+
+static void send_cancel_auth(struct device *device)
+{
+ DBusMessage *cancel;
+ char addr[18], *address = addr;
+ const char *uuid;
+
+ if (headset_get_type(device) == SVC_HEADSET)
+ uuid = HSP_AG_UUID;
+ else
+ uuid = HFP_AG_UUID;
+
+ cancel = dbus_message_new_method_call("org.bluez", "/org/bluez",
+ "org.bluez.Database",
+ "CancelAuthorizationRequest");
+ if (!cancel) {
+ error("Unable to allocate new method call");
+ return;
+ }
+
+ ba2str(&device->dst, addr);
+
+ dbus_message_append_args(cancel, DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID);
+
+ send_message_and_unref(connection, cancel);
+}
+
+static void auth_cb(DBusPendingCall *call, void *data)
+{
+ struct device *device = data;
+ DBusMessage *reply = dbus_pending_call_steal_reply(call);
+ DBusError err;
+
+ dbus_error_init(&err);
+ if (dbus_set_error_from_message(&err, reply)) {
+ error("Access denied: %s", err.message);
+ if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
+ debug("Canceling authorization request");
+ send_cancel_auth(device);
+ }
+ dbus_error_free(&err);
+ headset_close_rfcomm(device);
+ } else {
+ char hs_address[18];
+
+ headset_set_state(device, HEADSET_STATE_CONNECTED);
+
+ ba2str(&device->dst, hs_address);
+
+ debug("Accepted headset connection from %s for %s",
+ hs_address, device->path);
+ }
+
+ dbus_message_unref(reply);
+}
+
+static gboolean gateway_io_cb(GIOChannel *chan, GIOCondition cond, void *data)
+{
+ int srv_sk, cli_sk;
+ struct sockaddr_rc addr;
+ socklen_t size;
+ char hs_address[18], *address = hs_address;
+ const char *uuid;
+ struct device *device;
+ DBusMessage *auth;
+ DBusPendingCall *pending;
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ error("Hangup or error on rfcomm server socket");
+ g_io_channel_close(chan);
+ raise(SIGTERM);
+ return FALSE;
+ }
+
+ srv_sk = g_io_channel_unix_get_fd(chan);
+
+ size = sizeof(struct sockaddr_rc);
+ cli_sk = accept(srv_sk, (struct sockaddr *) &addr, &size);
+ if (cli_sk < 0) {
+ error("accept: %s (%d)", strerror(errno), errno);
+ return TRUE;
+ }
+
+ device = manager_device_connected(&addr.rc_bdaddr);
+ if (!device) {
+ close(cli_sk);
+ return TRUE;
+ }
+
+ if (headset_get_state(device) > HEADSET_STATE_DISCONNECTED) {
+ debug("Refusing new connection since one already exists");
+ close(cli_sk);
+ return TRUE;
+ }
+
+ if (headset_connect_rfcomm(device, cli_sk) < 0) {
+ error("Allocating new GIOChannel failed!");
+ close(cli_sk);
+ return TRUE;
+ }
+
+ if (chan == hs_server) {
+ headset_set_type(device, SVC_HEADSET);
+ uuid = HSP_AG_UUID;
+ } else {
+ headset_set_type(device, SVC_HANDSFREE);
+ uuid = HFP_AG_UUID;
+ }
+
+ auth = dbus_message_new_method_call("org.bluez", "/org/bluez",
+ "org.bluez.Database",
+ "RequestAuthorization");
+ if (!auth) {
+ error("Unable to allocate RequestAuthorization method call");
+ goto failed;
+ }
+
+ ba2str(&device->dst, hs_address);
+
+ dbus_message_append_args(auth, DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID);
+
+ if (!dbus_connection_send_with_reply(connection, auth, &pending, -1)) {
+ error("Sending of authorization request failed");
+ goto failed;
+ }
+
+ dbus_pending_call_set_notify(pending, auth_cb, device, NULL);
+ dbus_pending_call_unref(pending);
+ dbus_message_unref(auth);
+
+ return TRUE;
+
+failed:
+ headset_close_rfcomm(device);
+
+ return TRUE;
+}
+
+static GIOChannel *server_socket(uint8_t *channel)
+{
+ int sock, lm;
+ struct sockaddr_rc addr;
+ socklen_t sa_len;
+ GIOChannel *io;
+
+ sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
+ if (sock < 0) {
+ error("server socket: %s (%d)", strerror(errno), errno);
+ return NULL;
+ }
+
+ lm = RFCOMM_LM_SECURE;
+ if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
+ error("server setsockopt: %s (%d)", strerror(errno), errno);
+ close(sock);
+ return NULL;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.rc_family = AF_BLUETOOTH;
+ bacpy(&addr.rc_bdaddr, BDADDR_ANY);
+ addr.rc_channel = channel ? *channel : 0;
+
+ if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ error("server bind: %s", strerror(errno), errno);
+ close(sock);
+ return NULL;
+ }
+
+ if (listen(sock, 1) < 0) {
+ error("server listen: %s", strerror(errno), errno);
+ close(sock);
+ return NULL;
+ }
+
+ sa_len = sizeof(struct sockaddr_rc);
+ getsockname(sock, (struct sockaddr *) &addr, &sa_len);
+ *channel = addr.rc_channel;
+
+ io = g_io_channel_unix_new(sock);
+ if (!io) {
+ error("Unable to allocate new io channel");
+ close(sock);
+ return NULL;
+ }
+
+ return io;
+}
+
+int gateway_init(DBusConnection *conn, gboolean no_hfp, gboolean sco_hci)
+{
+ uint8_t chan = DEFAULT_HS_AG_CHANNEL;
+ sdp_buf_t buf;
+
+ connection = dbus_connection_ref(conn);
+
+ hs_server = server_socket(&chan);
+ if (!hs_server)
+ return -1;
+
+ if (gateway_hsp_ag_record(&buf, chan) < 0) {
+ error("Unable to allocate new service record");
+ return -1;
+ }
+
+ hs_record_id = gateway_add_ag_record(chan, &buf);
+ free(buf.data);
+ if (!hs_record_id) {
+ error("Unable to register HS AG service record");
+ g_io_channel_unref(hs_server);
+ hs_server = NULL;
+ return -1;
+ }
+
+ g_io_add_watch(hs_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ (GIOFunc) gateway_io_cb, NULL);
+
+ if (no_hfp)
+ return 0;
+
+ chan = DEFAULT_HF_AG_CHANNEL;
+
+ hf_server = server_socket(&chan);
+ if (!hf_server)
+ return -1;
+
+ if (gateway_hfp_ag_record(&buf, chan) < 0) {
+ error("Unable to allocate new service record");
+ return -1;
+ }
+
+ hf_record_id = gateway_add_ag_record(chan, &buf);
+ free(buf.data);
+ if (!hf_record_id) {
+ error("Unable to register HS AG service record");
+ g_io_channel_unref(hf_server);
+ hs_server = NULL;
+ return -1;
+ }
+
+ g_io_add_watch(hf_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ (GIOFunc) gateway_io_cb, NULL);
+
+ return 0;
+}
+
+void gateway_exit(void)
+{
+ if (hs_record_id) {
+ gateway_remove_ag_record(hs_record_id);
+ hs_record_id = 0;
+ }
+
+ if (hs_server) {
+ g_io_channel_unref(hs_server);
+ hs_server = NULL;
+ }
+
+ if (hf_record_id) {
+ gateway_remove_ag_record(hf_record_id);
+ hf_record_id = 0;
+ }
+
+ if (hf_server) {
+ g_io_channel_unref(hf_server);
+ hf_server = NULL;
+ }
+
+ dbus_connection_unref(connection);
+ connection = NULL;
+}
Added: bluez-utils/branches/upstream/current/audio/gateway.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/gateway.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/gateway.h (added)
+++ bluez-utils/branches/upstream/current/audio/gateway.h Wed Jul 4 13:37:57 2007
@@ -1,0 +1,30 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#define AUDIO_GATEWAY_INTERFACE "org.bluez.audio.Gateway"
+
+struct gateway;
+
+int gateway_init(DBusConnection *conn, gboolean disable_hfp, gboolean sco_hci);
+
+void gateway_exit(void);
Modified: bluez-utils/branches/upstream/current/audio/headset.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/headset.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/headset.c (original)
+++ bluez-utils/branches/upstream/current/audio/headset.c Wed Jul 4 13:37:57 2007
@@ -53,45 +53,31 @@
#include "dbus-helper.h"
#include "logging.h"
#include "manager.h"
-#include "headset.h"
-
-#define DEFAULT_HS_AG_CHANNEL 12
+#include "error.h"
#define RING_INTERVAL 3000
-typedef enum {
- HEADSET_EVENT_KEYPRESS,
- HEADSET_EVENT_GAIN,
- HEADSET_EVENT_UNKNOWN,
- HEADSET_EVENT_INVALID
-} headset_event_t;
-
-typedef enum {
- HEADSET_STATE_UNAUTHORIZED,
- HEADSET_STATE_DISCONNECTED,
- HEADSET_STATE_CONNECT_IN_PROGRESS,
- HEADSET_STATE_CONNECTED,
- HEADSET_STATE_PLAY_IN_PROGRESS,
- HEADSET_STATE_PLAYING,
-} headset_state_t;
+#define BUF_SIZE 1024
+
+#define HEADSET_GAIN_SPEAKER 'S'
+#define HEADSET_GAIN_MICROPHONE 'M'
struct pending_connect {
- int ch;
DBusMessage *msg;
GIOChannel *io;
+ guint io_id;
+ int sock;
+ struct ipc_packet *pkt;
};
struct headset {
- char object_path[128];
- bdaddr_t bda;
+ uint32_t hsp_handle;
+ uint32_t hfp_handle;
+
+ int rfcomm_ch;
GIOChannel *rfcomm;
GIOChannel *sco;
-
- char *input;
- GIOChannel *audio_input;
- char *output;
- GIOChannel *audio_output;
guint ring_timer;
@@ -99,20 +85,17 @@
int data_start;
int data_length;
+ headset_type_t type;
+
headset_state_t state;
struct pending_connect *pending_connect;
+
+ int sp_gain;
+ int mic_gain;
};
static DBusHandlerResult hs_disconnect(DBusConnection *conn, DBusMessage *msg,
void *data);
-
-static GIOChannel *hs_server = NULL;
-
-static uint32_t hs_record_id = 0;
-
-static GSList *headsets = NULL;
-
-static DBusConnection *connection = NULL;
static void pending_connect_free(struct pending_connect *c)
{
@@ -123,153 +106,7 @@
g_free(c);
}
-static DBusHandlerResult error_reply(DBusConnection *conn, DBusMessage *msg,
- const char *name, const char *descr)
-{
- DBusMessage *derr;
-
- if (!conn || !msg)
- return DBUS_HANDLER_RESULT_HANDLED;
-
- derr = dbus_message_new_error(msg, name, descr);
- if (!derr) {
- error("Unable to allocate new error return");
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
- }
-
- return send_message_and_unref(conn, derr);
-}
-
-static DBusHandlerResult err_already_connected(DBusConnection *conn, DBusMessage *msg)
-{
- return error_reply(conn, msg, "org.bluez.audio.Error.AlreadyConnected",
- "Already connected to a device");
-}
-
-static DBusHandlerResult err_not_connected(DBusConnection *conn, DBusMessage *msg)
-{
- return error_reply(conn, msg, "org.bluez.audio.Error.NotConnected",
- "Not connected to any device");
-}
-
-static DBusHandlerResult err_not_supported(DBusConnection *conn, DBusMessage *msg)
-{
- return error_reply(conn, msg, "org.bluez.audio.Error.NotSupported",
- "The service is not supported by the remote device");
-}
-
-static DBusHandlerResult err_connect_failed(DBusConnection *conn, DBusMessage *msg, int err)
-{
- return error_reply(conn, msg, "org.bluez.audio.Error.ConnectFailed",
- strerror(err));
-}
-
-static DBusHandlerResult err_failed(DBusConnection *conn, DBusMessage *msg)
-{
- return error_reply(conn, msg, "org.bluez.audio.Error.Failed", "Failed");
-}
-
-static gint headset_bda_cmp(gconstpointer headset, gconstpointer bda)
-{
- const struct headset *hs = headset;
-
- return bacmp(&hs->bda, bda);
-}
-
-static gboolean headset_close_output(struct headset *hs)
-{
- assert(hs != NULL);
-
- if (hs->audio_output == NULL)
- return FALSE;
-
- g_io_channel_close(hs->audio_output);
- g_io_channel_unref(hs->audio_output);
- hs->audio_output = NULL;
-
- return TRUE;
-}
-
-/* FIXME: in the furture, that would be great to provide user space alsa driver (not plugin) */
-static gboolean headset_open_output(struct headset *hs, const char *output)
-{
- int out;
-
- assert(hs != NULL && output != NULL);
-
- headset_close_output(hs);
- if (output && hs->output) {
- g_free(hs->output);
- hs->output = g_strdup(output);
- }
-
- assert(hs->output);
-
- out = open(hs->output, O_WRONLY | O_SYNC | O_CREAT);
-
- if (out < 0) {
- error("open(%s): %s %d", hs->output, strerror(errno), errno);
- return FALSE;
- }
-
- hs->audio_output = g_io_channel_unix_new(out);
- if (!hs->audio_output) {
- error("Allocating new channel for audio output!");
- return FALSE;
- }
-
- g_io_channel_set_close_on_unref(hs->audio_output, TRUE);
-
- return TRUE;
-}
-
-static gboolean headset_close_input(struct headset *hs)
-{
- assert(hs != NULL);
-
- if (hs->audio_input == NULL)
- return FALSE;
-
- g_io_channel_close(hs->audio_input);
- g_io_channel_unref(hs->audio_input);
- hs->audio_input = NULL;
-
- return TRUE;
-}
-
-#if 0
-static gboolean headset_open_input(struct headset *hs, const char *input)
-{
- int in;
-
- assert(hs != NULL);
-
- /* we keep the input name, and NULL can be use to reopen */
- if (input && hs->input) {
- g_free(hs->input);
- hs->input = g_strdup(input);
- }
-
- assert(hs->input);
-
- in = open(hs->input, O_RDONLY | O_NOCTTY);
-
- if (in < 0) {
- error("open(%s): %s %d", hs->input, strerror(errno), errno);
- return FALSE;
- }
-
- hs->audio_input = g_io_channel_unix_new(in);
- if (!hs->audio_input) {
- error("Allocating new channel for audio input!");
- return FALSE;
- }
-
- return TRUE;
-}
-#endif
-
-static void hs_signal_gain_setting(struct headset *hs, const char *buf)
+static void hs_signal_gain_setting(struct device *device, const char *buf)
{
const char *name;
dbus_uint16_t gain;
@@ -279,27 +116,39 @@
return;
}
+ gain = (dbus_uint16_t) strtol(&buf[5], NULL, 10);
+
+ if (gain > 15) {
+ error("Invalid gain value received: %u", gain);
+ return;
+ }
+
switch (buf[3]) {
- case 'S':
+ case HEADSET_GAIN_SPEAKER:
+ if (device->headset->sp_gain == gain)
+ return;
name = "SpeakerGainChanged";
+ device->headset->sp_gain = gain;
break;
- case 'M':
+ case HEADSET_GAIN_MICROPHONE:
+ if (device->headset->mic_gain == gain)
+ return;
name = "MicrophoneGainChanged";
+ device->headset->mic_gain = gain;
break;
default:
error("Unknown gain setting");
return;
}
- gain = (dbus_uint16_t) strtol(&buf[5], NULL, 10);
-
- dbus_connection_emit_signal(connection, hs->object_path,
+ dbus_connection_emit_signal(device->conn, device->path,
AUDIO_HEADSET_INTERFACE, name,
DBUS_TYPE_UINT16, &gain,
DBUS_TYPE_INVALID);
}
-static headset_event_t parse_headset_event(const char *buf, char *rsp, int rsp_len)
+static headset_event_t parse_headset_event(const char *buf, char *rsp,
+ int rsp_len)
{
printf("Received: %s\n", buf);
@@ -321,28 +170,24 @@
return HEADSET_EVENT_UNKNOWN;
}
-static void close_sco(struct headset *hs)
-{
+static void close_sco(struct device *device)
+{
+ struct headset *hs = device->headset;
+
g_io_channel_close(hs->sco);
g_io_channel_unref(hs->sco);
hs->sco = NULL;
- if (hs->audio_output) {
- g_io_channel_unref(hs->audio_output);
- hs->audio_output = NULL;
- }
- if (hs->audio_input)
- headset_close_input(hs);
assert(hs->rfcomm);
hs->state = HEADSET_STATE_CONNECTED;
- dbus_connection_emit_signal(connection, hs->object_path,
+ dbus_connection_emit_signal(device->conn, device->path,
AUDIO_HEADSET_INTERFACE, "Stopped",
DBUS_TYPE_INVALID);
}
-
static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
- struct headset *hs)
-{
+ struct device *device)
+{
+ struct headset *hs;
unsigned char buf[BUF_SIZE];
char *cr, rsp[BUF_SIZE];
gsize bytes_read = 0;
@@ -353,10 +198,13 @@
if (cond & G_IO_NVAL)
return FALSE;
+ hs = device->headset;
+
if (cond & (G_IO_ERR | G_IO_HUP))
goto failed;
- err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf) - 1, &bytes_read);
+ err = g_io_channel_read(chan, (gchar *) buf, sizeof(buf) - 1,
+ &bytes_read);
if (err != G_IO_ERROR_NONE)
goto failed;
@@ -385,9 +233,10 @@
memset(rsp, 0, sizeof(rsp));
- switch (parse_headset_event(&hs->buf[hs->data_start], rsp, sizeof(rsp))) {
+ switch (parse_headset_event(&hs->buf[hs->data_start], rsp,
+ sizeof(rsp))) {
case HEADSET_EVENT_GAIN:
- hs_signal_gain_setting(hs, &hs->buf[hs->data_start] + 2);
+ hs_signal_gain_setting(device, &hs->buf[hs->data_start] + 2);
break;
case HEADSET_EVENT_KEYPRESS:
@@ -396,7 +245,7 @@
hs->ring_timer = 0;
}
- dbus_connection_emit_signal(connection, hs->object_path,
+ dbus_connection_emit_signal(device->conn, device->path,
AUDIO_HEADSET_INTERFACE,
"AnswerRequested",
DBUS_TYPE_INVALID);
@@ -414,9 +263,10 @@
err = G_IO_ERROR_NONE;
while (err == G_IO_ERROR_NONE && total_bytes_written < count) {
- /* FIXME: make it async */
- err = g_io_channel_write(hs->rfcomm, rsp + total_bytes_written,
- count - total_bytes_written, &bytes_written);
+ err = g_io_channel_write(hs->rfcomm,
+ rsp + total_bytes_written,
+ count - total_bytes_written,
+ &bytes_written);
if (err != G_IO_ERROR_NONE)
error("Error while writting to the audio output channel");
total_bytes_written += bytes_written;
@@ -432,169 +282,74 @@
failed:
if (hs->sco)
- close_sco(hs);
- hs_disconnect(NULL, NULL, hs);
+ close_sco(device);
+ hs_disconnect(NULL, NULL, device);
return FALSE;
}
-static void send_cancel_auth(struct headset *hs)
-{
- DBusMessage *cancel;
- char addr[18], *address = addr;
- const char *uuid = "";
-
- cancel = dbus_message_new_method_call("org.bluez", "/org/bluez",
- "org.bluez.Database",
- "CancelAuthorizationRequest");
- if (!cancel) {
- error("Unable to allocate new method call");
- return;
- }
-
- ba2str(&hs->bda, addr);
-
- dbus_message_append_args(cancel, DBUS_TYPE_STRING, &address,
- DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID);
-
- send_message_and_unref(connection, cancel);
-}
-
-static void auth_callback(DBusPendingCall *call, void *data)
-{
- struct headset *hs = data;
- DBusMessage *reply = dbus_pending_call_steal_reply(call);
- DBusError err;
-
- dbus_error_init(&err);
- if (dbus_set_error_from_message(&err, reply)) {
- error("Access denied: %s", err.message);
- if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
- debug("Canceling authorization request");
- send_cancel_auth(hs);
- }
- dbus_error_free(&err);
- g_io_channel_close(hs->rfcomm);
- g_io_channel_unref(hs->rfcomm);
- hs->rfcomm = NULL;
- } else {
- char hs_address[18];
-
- g_io_add_watch(hs->rfcomm, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- (GIOFunc) rfcomm_io_cb, hs);
-
- ba2str(&hs->bda, hs_address);
-
- debug("Accepted connection from %s for %s", hs_address, hs->object_path);
-
- hs->state = HEADSET_STATE_CONNECTED;
- dbus_connection_emit_signal(connection, hs->object_path,
- AUDIO_HEADSET_INTERFACE,
- "Connected",
- DBUS_TYPE_INVALID);
- }
-
- dbus_message_unref(reply);
-}
-
-static gboolean audio_input_to_sco_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
- struct headset *hs = data;
- char buf[1024];
- gsize bytes_read;
- gsize bytes_written, total_bytes_written;
- GIOError err;
+static gboolean sco_cb(GIOChannel *chan, GIOCondition cond,
+ struct device *device)
+{
+ struct headset *hs;
if (cond & G_IO_NVAL)
return FALSE;
- if (cond & (G_IO_HUP | G_IO_ERR))
- goto failed;
-
- err = g_io_channel_read(chan, buf, sizeof(buf), &bytes_read);
- if (err != G_IO_ERROR_NONE)
- goto failed;
-
- total_bytes_written = bytes_written = 0;
- err = G_IO_ERROR_NONE;
-
- while (err == G_IO_ERROR_NONE && total_bytes_written < bytes_read) {
- /* FIXME: make it async */
- err = g_io_channel_write(hs->sco, buf + total_bytes_written,
- bytes_read - total_bytes_written, &bytes_written);
+ hs = device->headset;
+
+ error("Audio connection got disconnected");
+
+ if (hs->sco)
+ close_sco(device);
+
+ return FALSE;
+}
+
+static GIOError headset_send(struct headset *hs, const char *str)
+{
+ GIOError err;
+ gsize total_written, written, count;
+
+ assert(hs != NULL);
+
+ if (hs->state < HEADSET_STATE_CONNECTED || !hs->rfcomm) {
+ error("headset_send: the headset is not connected");
+ return G_IO_ERROR_UNKNOWN;
+ }
+
+ count = strlen(str);
+ written = total_written = 0;
+
+ while (total_written < count) {
+ err = g_io_channel_write(hs->rfcomm, str + total_written,
+ count - total_written, &written);
if (err != G_IO_ERROR_NONE)
- error("Error while writting to the audio output channel");
- total_bytes_written += bytes_written;
- };
-
- return TRUE;
-
-failed:
- headset_close_input(hs);
- return FALSE;
-}
-
-static gboolean sco_input_to_audio_output_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
- struct headset *hs = data;
- char buf[1024];
- gsize bytes_read;
- gsize bytes_written, total_bytes_written;
- GIOError err;
-
- if (cond & G_IO_NVAL)
- return FALSE;
-
- if (cond & (G_IO_HUP | G_IO_ERR))
- goto disconn;
-
- if (!hs->audio_output && hs->output)
- headset_open_output(hs, hs->output);
-
- err = g_io_channel_read(chan, buf, sizeof(buf), &bytes_read);
-
- if (err != G_IO_ERROR_NONE)
- goto disconn;
-
- if (!hs->audio_output) {
- error("got %d bytes audio but have nowhere to write it", bytes_read);
- return TRUE;
- }
-
- total_bytes_written = bytes_written = 0;
- err = G_IO_ERROR_NONE;
-
- while (err == G_IO_ERROR_NONE && total_bytes_written < bytes_read) {
- /* FIXME: make it async */
- err = g_io_channel_write(hs->audio_output, buf + total_bytes_written,
- bytes_read - total_bytes_written, &bytes_written);
- if (err != G_IO_ERROR_NONE) {
- error("Error while writting to the audio output channel");
- }
- total_bytes_written += bytes_written;
- };
-
- return TRUE;
-
-disconn:
- error("Audio connection got disconnected");
- if (hs->sco)
- close_sco(hs);
- return FALSE;
+ return err;
+ total_written += written;
+ }
+
+ return G_IO_ERROR_NONE;
}
static gboolean sco_connect_cb(GIOChannel *chan, GIOCondition cond,
- struct headset *hs)
-{
+ struct device *device)
+{
+ struct headset *hs;
int ret, sk, err, flags;
socklen_t len;
DBusMessage *reply;
+ char str[13];
if (cond & G_IO_NVAL)
return FALSE;
- assert(hs != NULL && hs->pending_connect != NULL &&
- hs->sco == NULL && hs->state == HEADSET_STATE_PLAY_IN_PROGRESS);
+ hs = device->headset;
+
+ assert(hs != NULL);
+ assert(hs->pending_connect != NULL);
+ assert(hs->sco == NULL);
+ assert(hs->state == HEADSET_STATE_PLAY_IN_PROGRESS);
sk = g_io_channel_unix_get_fd(chan);
@@ -611,38 +366,52 @@
goto failed;
}
- debug("SCO socket opened for headset %s", hs->object_path);
-
+ debug("SCO socket opened for headset %s", device->path);
+
+ info("SCO fd=%d", sk);
hs->sco = chan;
hs->pending_connect->io = NULL;
flags = G_IO_ERR | G_IO_HUP | G_IO_NVAL;
- if (hs->audio_output)
- flags |= G_IO_IN;
-
- g_io_add_watch(hs->sco, flags, sco_input_to_audio_output_cb, hs);
-
- reply = dbus_message_new_method_return(hs->pending_connect->msg);
- if (reply)
- send_message_and_unref(connection, reply);
-
- /* FIXME: do we allow both? pull & push model at the same time on sco && audio_input? */
- if (hs->audio_input)
- g_io_add_watch(hs->audio_input, G_IO_IN | G_IO_NVAL,
- audio_input_to_sco_cb, hs);
+
+ g_io_add_watch(hs->sco, flags, (GIOFunc) sco_cb, device);
+
+ if (hs->pending_connect->msg) {
+ reply = dbus_message_new_method_return(hs->pending_connect->msg);
+ if (reply)
+ send_message_and_unref(device->conn, reply);
+ }
+ else if (hs->pending_connect->pkt) {
+ headset_get_config(device, hs->pending_connect->sock,
+ hs->pending_connect->pkt);
+ unix_send_cfg(hs->pending_connect->sock,
+ hs->pending_connect->pkt);
+ }
pending_connect_free(hs->pending_connect);
hs->pending_connect = NULL;
+ fcntl(sk, F_SETFL, 0);
+
hs->state = HEADSET_STATE_PLAYING;
- dbus_connection_emit_signal(connection, hs->object_path,
+ dbus_connection_emit_signal(device->conn, device->path,
AUDIO_HEADSET_INTERFACE,
"Playing", DBUS_TYPE_INVALID);
+ if (hs->sp_gain >= 0) {
+ snprintf(str, sizeof(str) - 1, "\r\n+VGS=%u\r\n", hs->sp_gain);
+ headset_send(device->headset, str);
+ }
+
+ if (hs->mic_gain >= 0) {
+ snprintf(str, sizeof(str) - 1, "\r\n+VGM=%u\r\n", hs->sp_gain);
+ headset_send(device->headset, str);
+ }
+
return FALSE;
failed:
- err_connect_failed(connection, hs->pending_connect->msg, err);
+ err_connect_failed(device->conn, hs->pending_connect->msg, strerror(err));
if (hs->pending_connect->io)
g_io_channel_close(hs->pending_connect->io);
pending_connect_free(hs->pending_connect);
@@ -654,18 +423,87 @@
return FALSE;
}
-static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond, struct headset *hs)
-{
+static int sco_connect(struct device *device, struct pending_connect *c)
+{
+ struct headset *hs = device->headset;
+ struct sockaddr_sco addr;
+ gboolean do_callback = FALSE;
+ int sk, err;
+
+ sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+ if (sk < 0) {
+ err = errno;
+ error("socket(BTPROTO_SCO): %s (%d)", strerror(err), err);
+ return -err;
+ }
+
+ c->io = g_io_channel_unix_new(sk);
+ if (!c->io) {
+ close(sk);
+ return -EINVAL;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ bacpy(&addr.sco_bdaddr, BDADDR_ANY);
+
+ if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ err = errno;
+ error("socket(BTPROTO_SCO): %s (%d)", strerror(err), err);
+ return -err;
+ }
+
+ if (set_nonblocking(sk) < 0) {
+ err = errno;
+ return -err;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sco_family = AF_BLUETOOTH;
+ bacpy(&addr.sco_bdaddr, &device->dst);
+
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ if (!(errno == EAGAIN || errno == EINPROGRESS)) {
+ err = errno;
+ error("connect: %s (%d)", strerror(errno), errno);
+ return -err;
+ }
+
+ debug("SCO connect in progress");
+ c->io_id = g_io_add_watch(c->io,
+ G_IO_OUT | G_IO_NVAL | G_IO_ERR | G_IO_HUP,
+ (GIOFunc) sco_connect_cb, device);
+ } else {
+ debug("SCO connect succeeded with first try");
+ do_callback = TRUE;
+ }
+
+ hs->state = HEADSET_STATE_PLAY_IN_PROGRESS;
+ hs->pending_connect = c;
+
+ if (do_callback)
+ sco_connect_cb(c->io, G_IO_OUT, device);
+
+ return 0;
+}
+
+static gboolean rfcomm_connect_cb(GIOChannel *chan, GIOCondition cond,
+ struct device *device)
+{
+ struct headset *hs;
char hs_address[18];
int sk, ret, err;
socklen_t len;
-
+
if (cond & G_IO_NVAL)
return FALSE;
- assert(hs != NULL && hs->pending_connect != NULL &&
- hs->rfcomm == NULL &&
- hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS);
+ hs = device->headset;
+
+ assert(hs != NULL);
+ assert(hs->pending_connect != NULL);
+ assert(hs->rfcomm == NULL);
+ assert(hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS);
sk = g_io_channel_unix_get_fd(chan);
@@ -682,26 +520,26 @@
goto failed;
}
- ba2str(&hs->bda, hs_address);
+ ba2str(&device->dst, hs_address);
hs->rfcomm = chan;
hs->pending_connect->io = NULL;
hs->state = HEADSET_STATE_CONNECTED;
- dbus_connection_emit_signal(connection, hs->object_path,
+ dbus_connection_emit_signal(device->conn, device->path,
AUDIO_HEADSET_INTERFACE,
"Connected", DBUS_TYPE_INVALID);
debug("Connected to %s", hs_address);
g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
- (GIOFunc) rfcomm_io_cb, hs);
+ (GIOFunc) rfcomm_io_cb, device);
if (hs->pending_connect->msg) {
DBusMessage *reply;
reply = dbus_message_new_method_return(hs->pending_connect->msg);
if (reply)
- send_message_and_unref(connection, reply);
+ send_message_and_unref(device->conn, reply);
}
pending_connect_free(hs->pending_connect);
@@ -710,7 +548,7 @@
return FALSE;
failed:
- err_connect_failed(connection, hs->pending_connect->msg, err);
+ err_connect_failed(device->conn, hs->pending_connect->msg, strerror(err));
if (hs->pending_connect->io)
g_io_channel_close(hs->pending_connect->io);
pending_connect_free(hs->pending_connect);
@@ -721,18 +559,20 @@
return FALSE;
}
-static int rfcomm_connect(struct headset *hs, int *err)
-{
+static int rfcomm_connect(struct device *device, int *err)
+{
+ struct headset *hs = device->headset;
struct sockaddr_rc addr;
char address[18];
int sk;
- assert(hs != NULL && hs->pending_connect != NULL &&
- hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS);
-
- ba2str(&hs->bda, address);
-
- debug("Connecting to %s channel %d", address, hs->pending_connect->ch);
+ assert(hs != NULL);
+ assert(hs->pending_connect != NULL);
+ assert(hs->state == HEADSET_STATE_CONNECT_IN_PROGRESS);
+
+ ba2str(&device->dst, address);
+
+ debug("Connecting to %s channel %d", address, hs->rfcomm_ch);
sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
if (sk < 0) {
@@ -755,17 +595,20 @@
}
if (set_nonblocking(sk) < 0) {
- *err = errno;
+ if (err)
+ *err = errno;
goto failed;
}
memset(&addr, 0, sizeof(addr));
addr.rc_family = AF_BLUETOOTH;
- bacpy(&addr.rc_bdaddr, &hs->bda);
- addr.rc_channel = hs->pending_connect->ch;
+ bacpy(&addr.rc_bdaddr, &device->dst);
+ addr.rc_channel = hs->rfcomm_ch;
hs->pending_connect->io = g_io_channel_unix_new(sk);
if (!hs->pending_connect->io) {
+ if (err)
+ *err = ENOMEM;
error("channel_unix_new failed in rfcomm connect");
goto failed;
}
@@ -774,17 +617,18 @@
if (!(errno == EAGAIN || errno == EINPROGRESS)) {
if (err)
*err = errno;
- error("connect() failed: %s (%d)", strerror(errno), errno);
+ error("connect() failed: %s (%d)", strerror(errno),
+ errno);
goto failed;
}
debug("Connect in progress");
g_io_add_watch(hs->pending_connect->io, G_IO_OUT | G_IO_NVAL,
- (GIOFunc) rfcomm_connect_cb, hs);
+ (GIOFunc) rfcomm_connect_cb, device);
} else {
debug("Connect succeeded with first try");
- rfcomm_connect_cb(hs->pending_connect->io, G_IO_OUT, hs);
+ rfcomm_connect_cb(hs->pending_connect->io, G_IO_OUT, device);
}
return 0;
@@ -796,200 +640,23 @@
return -1;
}
-static int create_ag_record(sdp_buf_t *buf, uint8_t ch)
-{
- sdp_list_t *svclass_id, *pfseq, *apseq, *root;
- uuid_t root_uuid, svclass_uuid, ga_svclass_uuid, l2cap_uuid, rfcomm_uuid;
- sdp_profile_desc_t profile;
- sdp_list_t *aproto, *proto[2];
- sdp_record_t record;
- sdp_data_t *channel;
- int ret;
-
- memset(&record, 0, sizeof(sdp_record_t));
-
- sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
- root = sdp_list_append(0, &root_uuid);
- sdp_set_browse_groups(&record, root);
-
- sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID);
- svclass_id = sdp_list_append(0, &svclass_uuid);
- sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
- svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
- sdp_set_service_classes(&record, svclass_id);
-
- sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
- profile.version = 0x0100;
- pfseq = sdp_list_append(0, &profile);
- sdp_set_profile_descs(&record, pfseq);
-
- sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
- proto[0] = sdp_list_append(0, &l2cap_uuid);
- apseq = sdp_list_append(0, proto[0]);
-
- sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
- proto[1] = sdp_list_append(0, &rfcomm_uuid);
- channel = sdp_data_alloc(SDP_UINT8, &ch);
- proto[1] = sdp_list_append(proto[1], channel);
- apseq = sdp_list_append(apseq, proto[1]);
-
- aproto = sdp_list_append(0, apseq);
- sdp_set_access_protos(&record, aproto);
-
- sdp_set_info_attr(&record, "Headset", 0, 0);
-
- if (sdp_gen_record_pdu(&record, buf) < 0)
- ret = -1;
- else
- ret = 0;
-
- sdp_data_free(channel);
- sdp_list_free(proto[0], 0);
- sdp_list_free(proto[1], 0);
- sdp_list_free(apseq, 0);
- sdp_list_free(pfseq, 0);
- sdp_list_free(aproto, 0);
- sdp_list_free(root, 0);
- sdp_list_free(svclass_id, 0);
- sdp_list_free(record.attrlist, (sdp_free_func_t) sdp_data_free);
- sdp_list_free(record.pattern, free);
-
- return ret;
-}
-
-static uint32_t headset_add_ag_record(uint8_t channel)
-{
- DBusMessage *msg, *reply;
- DBusError derr;
- dbus_uint32_t rec_id;
- sdp_buf_t buf;
-
- msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
- "org.bluez.Database", "AddServiceRecord");
- if (!msg) {
- error("Can't allocate new method call");
- return 0;
- }
-
- if (create_ag_record(&buf, channel) < 0) {
- error("Unable to allocate new service record");
- dbus_message_unref(msg);
- return 0;
- }
-
- dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
- &buf.data, buf.data_size, DBUS_TYPE_INVALID);
-
- dbus_error_init(&derr);
- reply = dbus_connection_send_with_reply_and_block(connection, msg,
- -1, &derr);
-
- free(buf.data);
- dbus_message_unref(msg);
-
- if (dbus_error_is_set(&derr) || dbus_set_error_from_message(&derr, reply)) {
- error("Adding service record failed: %s", derr.message);
- dbus_error_free(&derr);
- return 0;
- }
-
- dbus_message_get_args(reply, &derr, DBUS_TYPE_UINT32, &rec_id,
- DBUS_TYPE_INVALID);
-
- if (dbus_error_is_set(&derr)) {
- error("Invalid arguments to AddServiceRecord reply: %s", derr.message);
- dbus_message_unref(reply);
- dbus_error_free(&derr);
- return 0;
- }
-
- dbus_message_unref(reply);
-
- debug("add_ag_record: got record id 0x%x", rec_id);
-
- return rec_id;
-}
-
-int headset_remove_ag_record(uint32_t rec_id)
-{
- DBusMessage *msg, *reply;
- DBusError derr;
-
- msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
- "org.bluez.Database", "RemoveServiceRecord");
- if (!msg) {
- error("Can't allocate new method call");
- return 0;
- }
-
- dbus_message_append_args(msg, DBUS_TYPE_UINT32, &rec_id,
- DBUS_TYPE_INVALID);
-
- dbus_error_init(&derr);
- reply = dbus_connection_send_with_reply_and_block(connection, msg,
- -1, &derr);
-
- dbus_message_unref(msg);
-
- if (dbus_error_is_set(&derr)) {
- error("Removing service record 0x%x failed: %s", rec_id, derr.message);
- dbus_error_free(&derr);
- return 0;
- }
-
- dbus_message_unref(reply);
-
- return 0;
-}
-
-static void finish_sdp_transaction(bdaddr_t *dba)
-{
- char address[18], *addr_ptr = address;
- DBusMessage *msg, *reply;
- DBusError derr;
-
- ba2str(dba, address);
-
- msg = dbus_message_new_method_call("org.bluez", "/org/bluez/hci0",
- "org.bluez.Adapter",
- "FinishRemoteServiceTransaction");
- if (!msg) {
- error("Unable to allocate new method call");
- return;
- }
-
- dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr,
- DBUS_TYPE_INVALID);
-
- dbus_error_init(&derr);
- reply = dbus_connection_send_with_reply_and_block(connection, msg,
- -1, &derr);
-
- dbus_message_unref(msg);
-
- if (dbus_error_is_set(&derr) || dbus_set_error_from_message(&derr, reply)) {
- error("FinishRemoteServiceTransaction(%s) failed: %s",
- address, derr.message);
- dbus_error_free(&derr);
- return;
- }
-
- dbus_message_unref(reply);
-}
-
static void get_record_reply(DBusPendingCall *call, void *data)
{
DBusMessage *reply;
DBusError derr;
uint8_t *array;
- int array_len, record_len, err = EIO;
+ int array_len, record_len, err = EIO, ch = -1;
sdp_record_t *record = NULL;
sdp_list_t *protos, *classes = NULL;
uuid_t uuid;
- struct headset *hs = data;
+ struct device *device = data;
+ struct headset *hs = device->headset;
struct pending_connect *c;
- assert(hs != NULL && hs->pending_connect && !hs->rfcomm);
+ assert(hs != NULL);
+ assert(hs->pending_connect);
+ assert(!hs->rfcomm);
+
c = hs->pending_connect;
reply = dbus_pending_call_steal_reply(call);
@@ -1002,14 +669,15 @@
}
if (!dbus_message_get_args(reply, NULL,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &array, &array_len,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &array, &array_len,
DBUS_TYPE_INVALID)) {
error("Unable to get args from GetRecordReply");
goto failed_not_supported;
}
if (!array) {
- error("Unable to get handle array from reply");
+ error("get_record_reply: Unable to get handle array from reply");
goto failed_not_supported;
}
@@ -1035,28 +703,33 @@
goto failed_not_supported;
}
- if ((uuid.type == SDP_UUID32 && uuid.value.uuid32 != HEADSET_SVCLASS_ID) ||
- (uuid.type == SDP_UUID16 && uuid.value.uuid16 != HEADSET_SVCLASS_ID)) {
+ if ((uuid.type == SDP_UUID32 &&
+ uuid.value.uuid32 != HEADSET_SVCLASS_ID) ||
+ (uuid.type == SDP_UUID16 &&
+ uuid.value.uuid16 != HEADSET_SVCLASS_ID)) {
error("Service classes did not contain the expected UUID");
goto failed_not_supported;
}
if (!sdp_get_access_protos(record, &protos)) {
- c->ch = sdp_get_proto_port(protos, RFCOMM_UUID);
- sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+ ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+ sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free,
+ NULL);
sdp_list_free(protos, NULL);
protos = NULL;
}
- if (c->ch == -1) {
+ if (ch == -1) {
error("Unable to extract RFCOMM channel from service record");
goto failed_not_supported;
}
- if (rfcomm_connect(hs, &err) < 0) {
+ hs->rfcomm_ch = ch;
+
+ if (rfcomm_connect(device, &err) < 0) {
error("Unable to connect");
- if (c->msg)
- err_connect_failed(connection, c->msg, err);
+ if (c->msg)
+ err_connect_failed(device->conn, c->msg, strerror(err));
goto failed;
}
@@ -1064,13 +737,13 @@
sdp_record_free(record);
dbus_message_unref(reply);
- finish_sdp_transaction(&hs->bda);
+ device_finish_sdp_transaction(device);
return;
failed_not_supported:
- if (c->msg)
- err_not_supported(connection, c->msg);
+ if (c->msg)
+ err_not_supported(device->conn, c->msg);
failed:
if (classes)
sdp_list_free(classes, free);
@@ -1081,17 +754,18 @@
pending_connect_free(hs->pending_connect);
hs->pending_connect = NULL;
hs->state = HEADSET_STATE_DISCONNECTED;
- finish_sdp_transaction(&hs->bda);
+ device_finish_sdp_transaction(device);
}
static DBusHandlerResult hs_stop(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- struct headset *hs = data;
+ struct device *device = data;
+ struct headset *hs = device->headset;
DBusMessage *reply = NULL;
if (!hs || !hs->sco)
- return err_not_connected(connection, msg);
+ return err_not_connected(conn, msg);
if (msg) {
reply = dbus_message_new_method_return(msg);
@@ -1099,20 +773,21 @@
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
- if (hs->state == HEADSET_STATE_PLAY_IN_PROGRESS && hs->pending_connect) {
+ if (hs->state == HEADSET_STATE_PLAY_IN_PROGRESS &&
+ hs->pending_connect) {
g_io_channel_close(hs->pending_connect->io);
if (hs->pending_connect->msg)
- err_connect_failed(connection, hs->pending_connect->msg,
- EINTR);
+ err_connect_failed(conn, hs->pending_connect->msg,
+ strerror(EINTR));
pending_connect_free(hs->pending_connect);
hs->pending_connect = NULL;
hs->state = HEADSET_STATE_CONNECTED;
}
- close_sco(hs);
+ close_sco(device);
if (reply)
- send_message_and_unref(connection, reply);
+ send_message_and_unref(conn, reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -1120,7 +795,8 @@
static DBusHandlerResult hs_is_playing(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- struct headset *hs = data;
+ struct device *device = data;
+ struct headset *hs = device->headset;
DBusMessage *reply;
dbus_bool_t playing;
@@ -1138,7 +814,7 @@
dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &playing,
DBUS_TYPE_INVALID);
- send_message_and_unref(connection, reply);
+ send_message_and_unref(conn, reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -1146,7 +822,8 @@
static DBusHandlerResult hs_disconnect(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- struct headset *hs = data;
+ struct device *device = data;
+ struct headset *hs = device->headset;
DBusMessage *reply = NULL;
char hs_address[18];
@@ -1159,7 +836,12 @@
}
if (hs->state > HEADSET_STATE_CONNECTED)
- hs_stop(NULL, NULL, hs);
+ hs_stop(NULL, NULL, device);
+
+ if (hs->ring_timer) {
+ g_source_remove(hs->ring_timer);
+ hs->ring_timer = 0;
+ }
if (hs->rfcomm) {
g_io_channel_close(hs->rfcomm);
@@ -1170,19 +852,22 @@
if (hs->pending_connect) {
if (hs->pending_connect->io)
g_io_channel_close(hs->pending_connect->io);
+ if (hs->pending_connect->io_id)
+ g_source_remove(hs->pending_connect->io_id);
if (hs->pending_connect->msg)
- err_connect_failed(connection, hs->pending_connect->msg,
- EINTR);
+ err_connect_failed(conn,
+ hs->pending_connect->msg,
+ strerror(EINTR));
pending_connect_free(hs->pending_connect);
hs->pending_connect = NULL;
}
hs->state = HEADSET_STATE_DISCONNECTED;
- ba2str(&hs->bda, hs_address);
- info("Disconnected from %s, %s", &hs_address, hs->object_path);
-
- dbus_connection_emit_signal(connection, hs->object_path,
+ ba2str(&device->dst, hs_address);
+ info("Disconnected from %s, %s", hs_address, device->path);
+
+ dbus_connection_emit_signal(device->conn, device->path,
AUDIO_HEADSET_INTERFACE,
"Disconnected", DBUS_TYPE_INVALID);
@@ -1190,33 +875,29 @@
hs->data_length = 0;
if (reply)
- send_message_and_unref(connection, reply);
+ send_message_and_unref(conn, reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
-static DBusHandlerResult hs_is_connected(DBusConnection *conn, DBusMessage *msg,
+static DBusHandlerResult hs_is_connected(DBusConnection *conn,
+ DBusMessage *msg,
void *data)
{
- struct headset *hs = data;
+ struct device *device = data;
DBusMessage *reply;
dbus_bool_t connected;
-
- assert(hs);
reply = dbus_message_new_method_return(msg);
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- if (hs->state >= HEADSET_STATE_CONNECTED)
- connected = TRUE;
- else
- connected = FALSE;
+ connected = (device->headset->state >= HEADSET_STATE_CONNECTED);
dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
DBUS_TYPE_INVALID);
- send_message_and_unref(connection, reply);
+ send_message_and_unref(conn, reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -1226,14 +907,17 @@
DBusMessage *msg = NULL, *reply;
DBusPendingCall *pending;
DBusError derr;
- struct headset *hs = data;
+ struct device *device = data;
+ struct headset *hs = device->headset;
struct pending_connect *c;
char address[18], *addr_ptr = address;
dbus_uint32_t *array = NULL;
dbus_uint32_t handle;
int array_len;
- assert(hs != NULL && hs->pending_connect);
+ assert(hs != NULL);
+ assert(hs->pending_connect);
+
c = hs->pending_connect;
reply = dbus_pending_call_steal_reply(call);
@@ -1242,53 +926,55 @@
if (dbus_set_error_from_message(&derr, reply)) {
error("GetRemoteServiceHandles failed: %s", derr.message);
if (c->msg) {
- if (dbus_error_has_name(&derr, "org.bluez.Error.ConnectionAttemptFailed"))
- err_connect_failed(connection, c->msg, EHOSTDOWN);
+ if (dbus_error_has_name(&derr,
+ "org.bluez.Error.ConnectionAttemptFailed"))
+ err_connect_failed(device->conn, c->msg,
+ strerror(EHOSTDOWN));
else
- err_not_supported(connection, c->msg);
+ err_not_supported(device->conn, c->msg);
}
dbus_error_free(&derr);
goto failed;
}
if (!dbus_message_get_args(reply, NULL,
- DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &array, &array_len,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ &array, &array_len,
DBUS_TYPE_INVALID)) {
-
error("Unable to get args from reply");
+ if (c->msg)
+ err_not_supported(device->conn, c->msg);
+ goto failed;
+ }
+
+ if (!array) {
+ error("get_handles_reply: Unable to get handle array from reply");
if (c->msg)
- err_not_supported(connection, c->msg);
- goto failed;
- }
-
- if (!array) {
- error("Unable to get handle array from reply");
- if (c->msg)
- err_not_supported(connection, c->msg);
+ err_not_supported(device->conn, c->msg);
goto failed;
}
if (array_len < 1) {
debug("No record handles found");
if (c->msg)
- err_not_supported(connection, c->msg);
+ err_not_supported(device->conn, c->msg);
goto failed;
}
if (array_len > 1)
debug("Multiple records found. Using the first one.");
- msg = dbus_message_new_method_call("org.bluez", "/org/bluez/hci0",
+ msg = dbus_message_new_method_call("org.bluez", device->adapter_path,
"org.bluez.Adapter",
"GetRemoteServiceRecord");
if (!msg) {
error("Unable to allocate new method call");
- if (c->msg)
- err_connect_failed(connection, c->msg, ENOMEM);
- goto failed;
- }
-
- ba2str(&hs->bda, address);
+ if (c->msg)
+ err_connect_failed(device->conn, c->msg, strerror(ENOMEM));
+ goto failed;
+ }
+
+ ba2str(&device->dst, address);
handle = array[0];
@@ -1296,14 +982,14 @@
DBUS_TYPE_UINT32, &handle,
DBUS_TYPE_INVALID);
- if (!dbus_connection_send_with_reply(connection, msg, &pending, -1)) {
+ if (!dbus_connection_send_with_reply(device->conn, msg, &pending, -1)) {
error("Sending GetRemoteServiceRecord failed");
if (c->msg)
- err_connect_failed(connection, c->msg, EIO);
- goto failed;
- }
-
- dbus_pending_call_set_notify(pending, get_record_reply, hs, NULL);
+ err_connect_failed(device->conn, c->msg, strerror(EIO));
+ goto failed;
+ }
+
+ dbus_pending_call_set_notify(pending, get_record_reply, device, NULL);
dbus_pending_call_unref(pending);
dbus_message_unref(msg);
dbus_message_unref(reply);
@@ -1314,26 +1000,28 @@
if (msg)
dbus_message_unref(msg);
dbus_message_unref(reply);
- hs_disconnect(NULL, NULL, hs);
+ hs_disconnect(NULL, NULL, device);
}
static DBusHandlerResult hs_connect(DBusConnection *conn, DBusMessage *msg,
void *data)
{
DBusPendingCall *pending;
- struct headset *hs = data;
- const char *hs_svc = "hsp";
+ struct device *device = data;
+ struct headset *hs = device->headset;
+ const char *hs_svc;
const char *addr_ptr;
char hs_address[18];
+ int err;
assert(hs != NULL);
if (hs->state > HEADSET_STATE_DISCONNECTED || hs->pending_connect)
- return err_already_connected(connection, msg);
+ return err_already_connected(conn, msg);
hs->pending_connect = g_try_new0(struct pending_connect, 1);
if (!hs->pending_connect) {
- error("Out of memory when allocating new struct pending_connect");
+ error("Out of memory when allocating struct pending_connect");
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
@@ -1341,7 +1029,20 @@
hs->pending_connect->msg = msg ? dbus_message_ref(msg) : NULL;
- msg = dbus_message_new_method_call("org.bluez", "/org/bluez/hci0",
+ hs->type = hs->hfp_handle ? SVC_HANDSFREE : SVC_HEADSET;
+
+ if (hs->rfcomm_ch > 0) {
+ if (rfcomm_connect(device, &err) < 0) {
+ error("Unable to connect");
+ pending_connect_free(hs->pending_connect);
+ hs->pending_connect = NULL;
+ hs->state = HEADSET_STATE_DISCONNECTED;
+ return err_connect_failed(conn, msg, strerror(err));
+ } else
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ msg = dbus_message_new_method_call("org.bluez", device->adapter_path,
"org.bluez.Adapter",
"GetRemoteServiceHandles");
if (!msg) {
@@ -1352,61 +1053,40 @@
return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
- ba2str(&hs->bda, hs_address);
+ if (hs->type == SVC_HEADSET)
+ hs_svc = "hsp";
+ else
+ hs_svc = "hfp";
+
+ ba2str(&device->dst, hs_address);
addr_ptr = hs_address;
dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr,
DBUS_TYPE_STRING, &hs_svc,
DBUS_TYPE_INVALID);
- if (!dbus_connection_send_with_reply(connection, msg, &pending, -1)) {
+ if (!dbus_connection_send_with_reply(conn, msg, &pending, -1)) {
error("Sending GetRemoteServiceHandles failed");
pending_connect_free(hs->pending_connect);
hs->pending_connect = NULL;
hs->state = HEADSET_STATE_DISCONNECTED;
dbus_message_unref(msg);
- return err_connect_failed(connection, msg, EIO);
- }
-
- dbus_pending_call_set_notify(pending, get_handles_reply, hs, NULL);
+ return err_connect_failed(conn, msg, strerror(EIO));
+ }
+
+ dbus_pending_call_set_notify(pending, get_handles_reply, device, NULL);
dbus_pending_call_unref(pending);
dbus_message_unref(msg);
return DBUS_HANDLER_RESULT_HANDLED;;
}
-static GIOError headset_send_ring(struct headset *hs)
-{
- const char *ring_str = "\r\nRING\r\n";
- GIOError err;
- gsize total_written, written, count;
-
- assert(hs != NULL);
- if (hs->state < HEADSET_STATE_CONNECTED || !hs->rfcomm) {
- error("the headset %s is not connected", hs->object_path);
- return G_IO_ERROR_UNKNOWN;
- }
-
- count = strlen(ring_str);
- written = total_written = 0;
-
- while (total_written < count) {
- err = g_io_channel_write(hs->rfcomm, ring_str + total_written,
- count - total_written, &written);
- if (err != G_IO_ERROR_NONE)
- return err;
- total_written += written;
- }
-
- return G_IO_ERROR_NONE;
-}
-
static gboolean ring_timer_cb(gpointer data)
{
- struct headset *hs = data;
-
- assert(hs != NULL);
-
- if (headset_send_ring(hs) != G_IO_ERROR_NONE)
+ struct device *device = data;
+
+ assert(device != NULL);
+
+ if (headset_send(device->headset, "\r\nRING\r\n") != G_IO_ERROR_NONE)
error("Sending RING failed");
return TRUE;
@@ -1415,13 +1095,14 @@
static DBusHandlerResult hs_ring(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- struct headset *hs = data;
+ struct device *device = data;
+ struct headset *hs = device->headset;
DBusMessage *reply = NULL;
assert(hs != NULL);
if (hs->state < HEADSET_STATE_CONNECTED)
- return err_not_connected(connection, msg);
+ return err_not_connected(conn, msg);
if (msg) {
reply = dbus_message_new_method_return(msg);
@@ -1430,32 +1111,34 @@
}
if (hs->ring_timer) {
- debug("Got Ring method call while ringing already in progress");
+ debug("IndicateCall received when already indicating");
goto done;
}
- if (headset_send_ring(hs) != G_IO_ERROR_NONE) {
+ if (headset_send(device->headset, "\r\nRING\r\n") != G_IO_ERROR_NONE) {
dbus_message_unref(reply);
- return err_failed(connection, msg);
- }
-
- hs->ring_timer = g_timeout_add(RING_INTERVAL, ring_timer_cb, hs);
+ return err_failed(conn, msg, "Failed");
+ }
+
+ hs->ring_timer = g_timeout_add(RING_INTERVAL, ring_timer_cb, device);
done:
if (reply)
- send_message_and_unref(connection, reply);
+ send_message_and_unref(conn, reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
-static DBusHandlerResult hs_cancel_ringing(DBusConnection *conn, DBusMessage *msg,
+static DBusHandlerResult hs_cancel_ringing(DBusConnection *conn,
+ DBusMessage *msg,
void *data)
{
- struct headset *hs = data;
+ struct device *device = data;
+ struct headset *hs = device->headset;
DBusMessage *reply = NULL;
if (hs->state < HEADSET_STATE_CONNECTED)
- return err_not_connected(connection, msg);
+ return err_not_connected(conn, msg);
if (msg) {
reply = dbus_message_new_method_return(msg);
@@ -1473,7 +1156,7 @@
done:
if (reply)
- send_message_and_unref(connection, reply);
+ send_message_and_unref(conn, reply);
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -1481,89 +1164,171 @@
static DBusHandlerResult hs_play(DBusConnection *conn, DBusMessage *msg,
void *data)
{
- struct headset *hs = data;
- struct sockaddr_sco addr;
+ struct device *device = data;
+ struct headset *hs = device->headset;
struct pending_connect *c;
- int sk, err;
if (hs->state < HEADSET_STATE_CONNECTED)
- return err_not_connected(connection, msg); /* FIXME: in progress error? */
+ return err_not_connected(conn, msg);
if (hs->state >= HEADSET_STATE_PLAY_IN_PROGRESS || hs->pending_connect)
- return err_already_connected(connection, msg);
+ return err_already_connected(conn, msg);
if (hs->sco)
- return err_already_connected(connection, msg);
+ return err_already_connected(conn, msg);
c = g_try_new0(struct pending_connect, 1);
if (!c)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- hs->state = HEADSET_STATE_PLAY_IN_PROGRESS;
-
c->msg = msg ? dbus_message_ref(msg) : NULL;
- sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
- if (sk < 0) {
- err = errno;
- error("socket(BTPROTO_SCO): %s (%d)", strerror(err), err);
- err_connect_failed(connection, msg, err);
- goto failed;
- }
-
- c->io = g_io_channel_unix_new(sk);
- if (!c->io) {
- close(sk);
- pending_connect_free(c);
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sco_family = AF_BLUETOOTH;
- bacpy(&addr.sco_bdaddr, BDADDR_ANY);
-
- if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
- err = errno;
- error("socket(BTPROTO_SCO): %s (%d)", strerror(err), err);
- err_connect_failed(connection, msg, err);
- goto failed;
- }
-
- if (set_nonblocking(sk) < 0) {
- err = errno;
- err_connect_failed(connection, msg, err);
- goto failed;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sco_family = AF_BLUETOOTH;
- bacpy(&addr.sco_bdaddr, &hs->bda);
-
- if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- if (!(errno == EAGAIN || errno == EINPROGRESS)) {
- err = errno;
- error("connect: %s (%d)", strerror(errno), errno);
- goto failed;
- }
-
- debug("Connect in progress");
-
- g_io_add_watch(c->io, G_IO_OUT | G_IO_NVAL,
- (GIOFunc) sco_connect_cb, hs);
- } else {
- debug("Connect succeeded with first try");
- sco_connect_cb(c->io, G_IO_OUT, hs);
- }
-
- hs->pending_connect = c;
+ if (sco_connect(device, c) < 0)
+ goto failed;
return 0;
-
failed:
if (c)
pending_connect_free(c);
return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult hs_get_speaker_gain(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ struct device *device = data;
+ struct headset *hs = device->headset;
+ DBusMessage *reply;
+ dbus_uint16_t gain;
+
+ assert(hs);
+
+ if (hs->state < HEADSET_STATE_CONNECTED || hs->sp_gain < 0)
+ return err_not_available(conn, msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ gain = (dbus_uint16_t) hs->sp_gain;
+
+ dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
+ DBUS_TYPE_INVALID);
+
+ send_message_and_unref(conn, reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult hs_get_mic_gain(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ struct device *device = data;
+ struct headset *hs = device->headset;
+ DBusMessage *reply;
+ dbus_uint16_t gain;
+
+ assert(hs);
+
+ if (hs->state < HEADSET_STATE_CONNECTED || hs->mic_gain < 0)
+ return err_not_available(conn, msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ gain = (dbus_uint16_t) hs->mic_gain;
+
+ dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
+ DBUS_TYPE_INVALID);
+
+ send_message_and_unref(conn, reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult hs_set_gain(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data, char type)
+{
+ struct device *device = data;
+ struct headset *hs = device->headset;
+ DBusMessage *reply;
+ DBusError derr;
+ dbus_uint16_t gain;
+ char str[13];
+
+ assert(hs);
+
+ if (hs->state < HEADSET_STATE_CONNECTED)
+ return err_not_connected(conn, msg);
+
+ dbus_error_init(&derr);
+ dbus_message_get_args(msg, &derr, DBUS_TYPE_UINT16, &gain,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_error_is_set(&derr)) {
+ err_invalid_args(conn, msg, derr.message);
+ dbus_error_free(&derr);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (gain > 15)
+ return err_invalid_args(conn, msg,
+ "Must be less than or equal to 15");
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ if (hs->state != HEADSET_STATE_PLAYING)
+ goto done;
+
+ snprintf(str, sizeof(str) - 1, "\r\n+VG%c=%u\r\n", type, gain);
+
+ if (headset_send(device->headset, str) != G_IO_ERROR_NONE) {
+ dbus_message_unref(reply);
+ return err_failed(conn, msg, "Unable to send to headset");
+ }
+
+done:
+ if (type == HEADSET_GAIN_SPEAKER) {
+ hs->sp_gain = gain;
+ dbus_connection_emit_signal(conn, device->path,
+ AUDIO_HEADSET_INTERFACE,
+ "SpeakerGainChanged",
+ DBUS_TYPE_UINT16, &gain,
+ DBUS_TYPE_INVALID);
+ }
+ else {
+ hs->mic_gain = gain;
+ dbus_connection_emit_signal(conn, device->path,
+ AUDIO_HEADSET_INTERFACE,
+ "MicrophoneGainChanged",
+ DBUS_TYPE_UINT16, &gain,
+ DBUS_TYPE_INVALID);
+ }
+
+ send_message_and_unref(conn, reply);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult hs_set_speaker_gain(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ return hs_set_gain(conn, msg, data, HEADSET_GAIN_SPEAKER);
+}
+
+static DBusHandlerResult hs_set_mic_gain(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ return hs_set_gain(conn, msg, data, HEADSET_GAIN_MICROPHONE);
}
static DBusMethodVTable headset_methods[] = {
@@ -1575,6 +1340,10 @@
{ "Play", hs_play, "", "" },
{ "Stop", hs_stop, "", "" },
{ "IsPlaying", hs_is_playing, "", "b" },
+ { "GetSpeakerGain", hs_get_speaker_gain, "", "q" },
+ { "GetMicrophoneGain", hs_get_mic_gain, "", "q" },
+ { "SetSpeakerGain", hs_set_speaker_gain, "q", "" },
+ { "SetMicrophoneGain", hs_set_mic_gain, "q", "" },
{ NULL, NULL, NULL, NULL }
};
@@ -1589,275 +1358,224 @@
{ NULL, NULL }
};
-static struct headset *headset_add_internal(const bdaddr_t *bda)
-{
- static int headset_uid = 0;
- struct headset *hs;
- GSList *match;
-
- match = g_slist_find_custom(headsets, bda, headset_bda_cmp);
- if (match)
- return match->data;
-
- hs = g_try_new0(struct headset, 1);
- if (!hs) {
- error("Allocating new hs connection struct failed!");
+static void headset_set_channel(struct headset *headset, sdp_record_t *record)
+{
+ int ch;
+ sdp_list_t *protos;
+
+ if (sdp_get_access_protos(record, &protos) < 0) {
+ error("Unable to get access protos from headset record");
+ return;
+ }
+
+ ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+
+ sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
+ sdp_list_free(protos, NULL);
+
+ if (ch > 0) {
+ headset->rfcomm_ch = ch;
+ debug("Discovered Headset service on RFCOMM channel %d", ch);
+ } else
+ error("Unable to get RFCOMM channel from Headset record");
+}
+
+void headset_update(void *device, sdp_record_t *record, uint16_t svc)
+{
+ struct headset *headset = ((struct device *) device)->headset;
+
+ switch (svc) {
+ case HANDSFREE_SVCLASS_ID:
+ if (headset->hfp_handle &&
+ (headset->hfp_handle != record->handle)) {
+ error("More than one HFP record found on device");
+ return;
+ }
+
+ headset->hfp_handle = record->handle;
+ break;
+
+ case HEADSET_SVCLASS_ID:
+ if (headset->hsp_handle &&
+ (headset->hsp_handle != record->handle)) {
+ error("More than one HSP record found on device");
+ return;
+ }
+
+ headset->hsp_handle = record->handle;
+
+ /* Ignore this record if we already have access to HFP */
+ if (headset->hfp_handle)
+ return;
+
+ break;
+
+ default:
+ debug("Invalid record passed to headset_update");
+ return;
+ }
+
+ headset_set_channel(headset, record);
+}
+
+struct headset *headset_init(void *device, sdp_record_t *record,
+ uint16_t svc)
+{
+ struct headset *headset;
+
+ headset = g_new0(struct headset, 1);
+ headset->rfcomm_ch = -1;
+ headset->sp_gain = -1;
+ headset->mic_gain = -1;
+
+ if (!record)
+ goto register_iface;
+
+ switch (svc) {
+ case HANDSFREE_SVCLASS_ID:
+ headset->hfp_handle = record->handle;
+ break;
+
+ case HEADSET_SVCLASS_ID:
+ headset->hsp_handle = record->handle;
+ break;
+
+ default:
+ debug("Invalid record passed to headset_init");
+ g_free(headset);
return NULL;
}
- snprintf(hs->object_path, sizeof(hs->object_path),
- HEADSET_PATH_BASE "%d", headset_uid++);
-
- if (!dbus_connection_create_object_path(connection, hs->object_path,
- hs, NULL)) {
- error("D-Bus failed to register %s path", hs->object_path);
- g_free(hs);
+register_iface:
+ if (!dbus_connection_register_interface(((struct device *) device)->conn,
+ ((struct device *) device)->path,
+ AUDIO_HEADSET_INTERFACE,
+ headset_methods,
+ headset_signals, NULL)) {
+ g_free(headset);
return NULL;
}
- if (!dbus_connection_register_interface(connection, hs->object_path,
+ if (record)
+ headset_set_channel(headset, record);
+
+ return headset;
+}
+
+void headset_free(void *device)
+{
+ struct headset *headset = ((struct device *) device)->headset;
+
+ if (headset->state != HEADSET_STATE_DISCONNECTED)
+ hs_disconnect(NULL, NULL, device);
+
+ g_free(headset);
+ headset = NULL;
+}
+
+int headset_get_config(void *device, int sock, struct ipc_packet *pkt)
+{
+ struct headset *headset = ((struct device *) device)->headset;
+ struct ipc_data_cfg *cfg = (struct ipc_data_cfg *) pkt->data;
+ int err = EINVAL;
+ struct pending_connect *c;
+
+ if (headset->sco == NULL) {
+ c = g_try_new0(struct pending_connect, 1);
+ if (c == NULL)
+ goto error;
+ c->sock = sock;
+ c->pkt = pkt;
+ if ((err = sco_connect(device, c)) < 0)
+ goto error;
+ return 0;
+ }
+
+ cfg->fd = g_io_channel_unix_get_fd(headset->sco);
+ cfg->fd_opt = CFG_FD_OPT_READWRITE;
+ cfg->encoding = 0;
+ cfg->bitpool = 0;
+ cfg->channels = 1;
+ cfg->pkt_len = 48;
+ cfg->sample_size = 2;
+ cfg->rate = 8000;
+
+ return 0;
+error:
+ cfg->fd = -1;
+ return -err;
+}
+
+headset_type_t headset_get_type(void *device)
+{
+ struct headset *headset = ((struct device *) device)->headset;
+
+ return headset->type;
+}
+
+void headset_set_type(void *device, headset_type_t type)
+{
+ struct headset *headset = ((struct device *) device)->headset;
+
+ headset->type = type;
+}
+
+int headset_connect_rfcomm(void *device, int sock)
+{
+ struct headset *headset = ((struct device *) device)->headset;
+
+ headset->rfcomm = g_io_channel_unix_new(sock);
+
+ return headset->rfcomm ? 0 : -EINVAL;
+}
+
+int headset_close_rfcomm(void *device)
+{
+ struct headset *headset = ((struct device *) device)->headset;
+
+ g_io_channel_close(headset->rfcomm);
+ g_io_channel_unref(headset->rfcomm);
+ headset->rfcomm = NULL;
+
+ return 0;
+}
+
+void headset_set_state(void *device, headset_state_t state)
+{
+ struct headset *headset = ((struct device *) device)->headset;
+
+ switch(state) {
+ case HEADSET_STATE_DISCONNECTED:
+ case HEADSET_STATE_CONNECT_IN_PROGRESS:
+ break;
+ case HEADSET_STATE_CONNECTED:
+ if (headset->rfcomm) {
+ char hs_address[18];
+
+ g_io_add_watch(headset->rfcomm,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ (GIOFunc) rfcomm_io_cb, device);
+
+ ba2str(&((struct device *) device)->dst, hs_address);
+
+ dbus_connection_emit_signal(((struct device *) device)->conn,
+ ((struct device *) device)->path,
AUDIO_HEADSET_INTERFACE,
- headset_methods,
- headset_signals, NULL)) {
- error("Failed to register %s interface to %s",
- AUDIO_HEADSET_INTERFACE, hs->object_path);
- dbus_connection_destroy_object_path(connection,
- hs->object_path);
- g_free(hs);
- return NULL;
- }
-
- bacpy(&hs->bda, bda);
-
- headsets = g_slist_append(headsets, hs);
-
- return hs;
-}
-
-const char *headset_add(const bdaddr_t *bda)
-{
- struct headset *hs;
-
- hs = headset_add_internal(bda);
- if (!hs)
- return NULL;
-
- return hs->object_path;
-}
-
-const char *headset_get(const bdaddr_t *bda)
-{
- GSList *match;
- struct headset *hs;
-
- match = g_slist_find_custom(headsets, bda, headset_bda_cmp);
- if (!match)
- return NULL;
-
- hs = match->data;
-
- return hs->object_path;
-}
-
-void headset_remove(const char *path)
-{
- struct headset *hs;
-
- if (!dbus_connection_get_object_user_data(connection, path,
- (void *) &hs))
- return;
-
- if (hs->state > HEADSET_STATE_DISCONNECTED)
- hs_disconnect(NULL, NULL, hs);
-
- if (!dbus_connection_destroy_object_path(connection, path))
- error("D-Bus failed to unregister %s path", path);
-
- headsets = g_slist_remove(headsets, hs);
-
- g_free(hs);
-}
-
-static gboolean headset_server_io_cb(GIOChannel *chan, GIOCondition cond, void *data)
-{
- int srv_sk, cli_sk;
- struct sockaddr_rc addr;
- socklen_t size;
- char hs_address[18], *address = hs_address;
- const char *uuid = "";
- struct headset *hs = NULL;
- DBusMessage *auth;
- DBusPendingCall *pending;
- GSList *match;
-
- if (cond & G_IO_NVAL)
- return FALSE;
-
- if (cond & (G_IO_HUP | G_IO_ERR)) {
- error("Hangup or error on rfcomm server socket");
- g_io_channel_close(chan);
- raise(SIGTERM);
- return FALSE;
- }
-
- srv_sk = g_io_channel_unix_get_fd(chan);
-
- size = sizeof(struct sockaddr_rc);
- cli_sk = accept(srv_sk, (struct sockaddr *) &addr, &size);
- if (cli_sk < 0) {
- error("accept: %s (%d)", strerror(errno), errno);
- return TRUE;
- }
-
- match = g_slist_find_custom(headsets, &addr.rc_bdaddr, headset_bda_cmp);
- if (!match) {
- hs = headset_add_internal(&addr.rc_bdaddr);
- if (!hs) {
- error("Unable to create a new headset object");
- close(cli_sk);
- return TRUE;
+ "Connected",
+ DBUS_TYPE_INVALID);
}
-
- manager_add_headset(hs->object_path);
- }
- else
- hs = match->data;
-
- if (hs->state > HEADSET_STATE_DISCONNECTED || hs->rfcomm) {
- debug("Refusing new connection since one already exists");
- close(cli_sk);
- return TRUE;
- }
-
- hs->rfcomm = g_io_channel_unix_new(cli_sk);
- if (!hs->rfcomm) {
- error("Allocating new GIOChannel failed!");
- close(cli_sk);
- return TRUE;
- }
-
- auth = dbus_message_new_method_call("org.bluez", "/org/bluez", "org.bluez.Database",
- "RequestAuthorization");
- if (!auth) {
- error("Unable to allocat new RequestAuthorization method call");
- goto failed;
- }
-
- ba2str(&hs->bda, hs_address);
-
- dbus_message_append_args(auth, DBUS_TYPE_STRING, &address,
- DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID);
-
- if (dbus_connection_send_with_reply(connection, auth, &pending, -1) == FALSE) {
- error("Sending of authorization request failed");
- goto failed;
- }
-
- dbus_pending_call_set_notify(pending, auth_callback, hs, NULL);
- dbus_pending_call_unref(pending);
- dbus_message_unref(auth);
-
- return TRUE;
-
-failed:
- if (hs->rfcomm) {
- g_io_channel_close(hs->rfcomm);
- g_io_channel_unref(hs->rfcomm);
- hs->rfcomm = NULL;
- }
-
- return TRUE;
-}
-
-static GIOChannel *server_socket(uint8_t *channel)
-{
- int sock, lm;
- struct sockaddr_rc addr;
- socklen_t sa_len;
- GIOChannel *io;
-
- sock = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
- if (sock < 0) {
- error("server socket: %s (%d)", strerror(errno), errno);
- return NULL;
- }
-
- lm = RFCOMM_LM_SECURE;
- if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
- error("server setsockopt: %s (%d)", strerror(errno), errno);
- close(sock);
- return NULL;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.rc_family = AF_BLUETOOTH;
- bacpy(&addr.rc_bdaddr, BDADDR_ANY);
- addr.rc_channel = 0;
-
- if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- error("server bind: %s", strerror(errno), errno);
- close(sock);
- return NULL;
- }
-
- if (listen(sock, 1) < 0) {
- error("server listen: %s", strerror(errno), errno);
- close(sock);
- return NULL;
- }
-
- sa_len = sizeof(struct sockaddr_rc);
- getsockname(sock, (struct sockaddr *) &addr, &sa_len);
- *channel = addr.rc_channel;
-
- io = g_io_channel_unix_new(sock);
- if (!io) {
- error("Unable to allocate new io channel");
- close(sock);
- return NULL;
- }
-
- return io;
-}
-
-int headset_init(DBusConnection *conn)
-{
- uint8_t chan = DEFAULT_HS_AG_CHANNEL;
-
- connection = dbus_connection_ref(conn);
-
- hs_server = server_socket(&chan);
- if (!hs_server)
- return -1;
-
- if (!hs_record_id)
- hs_record_id = headset_add_ag_record(chan);
-
- if (!hs_record_id) {
- error("Unable to register service record");
- g_io_channel_unref(hs_server);
- hs_server = NULL;
- return -1;
- }
-
- g_io_add_watch(hs_server, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- (GIOFunc) headset_server_io_cb, NULL);
-
- return 0;
-}
-
-void headset_exit(void)
-{
- if (hs_record_id) {
- headset_remove_ag_record(hs_record_id);
- hs_record_id = 0;
- }
-
- if (hs_server) {
- g_io_channel_unref(hs_server);
- hs_server = NULL;
- }
-
- dbus_connection_unref(connection);
- connection = NULL;
-}
+ break;
+ case HEADSET_STATE_PLAY_IN_PROGRESS:
+ case HEADSET_STATE_PLAYING:
+ break;
+ }
+
+ headset->state = state;
+}
+
+headset_state_t headset_get_state(void *device)
+{
+ struct headset *headset = ((struct device *) device)->headset;
+
+ return headset->state;
+}
Modified: bluez-utils/branches/upstream/current/audio/headset.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/headset.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/headset.h (original)
+++ bluez-utils/branches/upstream/current/audio/headset.h Wed Jul 4 13:37:57 2007
@@ -20,25 +20,54 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
-#ifndef __AUDIO_HEADSET_H
-#define __AUDIO_HEADSET_H
-
-#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
#include <dbus/dbus.h>
+#include "unix.h"
+
#define AUDIO_HEADSET_INTERFACE "org.bluez.audio.Headset"
-#define BUF_SIZE 1024
+#define DEFAULT_HS_AG_CHANNEL 12
+#define DEFAULT_HF_AG_CHANNEL 13
-const char *headset_get(const bdaddr_t *bda);
+typedef enum {
+ HEADSET_EVENT_KEYPRESS,
+ HEADSET_EVENT_GAIN,
+ HEADSET_EVENT_UNKNOWN,
+ HEADSET_EVENT_INVALID
+} headset_event_t;
-const char *headset_add(const bdaddr_t *bda);
+typedef enum {
+ HEADSET_STATE_DISCONNECTED = 0,
+ HEADSET_STATE_CONNECT_IN_PROGRESS,
+ HEADSET_STATE_CONNECTED,
+ HEADSET_STATE_PLAY_IN_PROGRESS,
+ HEADSET_STATE_PLAYING,
+} headset_state_t;
-void headset_remove(const char *path);
+typedef enum {
+ SVC_HEADSET,
+ SVC_HANDSFREE
+} headset_type_t;
-int headset_init(DBusConnection *conn);
+struct headset;
-void headset_exit(void);
+struct headset *headset_init(void *device, sdp_record_t *record,
+ uint16_t svc);
-#endif /* __AUDIO_HEADSET_H_ */
+void headset_free(void *device);
+
+void headset_update(void *device, sdp_record_t *record, uint16_t svc);
+
+int headset_get_config(void *device, int sock, struct ipc_packet *pkt);
+
+headset_type_t headset_get_type(void *device);
+void headset_set_type(void *device, headset_type_t type);
+
+int headset_connect_rfcomm(void *device, int sock);
+int headset_close_rfcomm(void *device);
+
+headset_state_t headset_get_state(void *device);
+void headset_set_state(void *device, headset_state_t state);
Modified: bluez-utils/branches/upstream/current/audio/ipc.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/ipc.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/ipc.h (original)
+++ bluez-utils/branches/upstream/current/audio/ipc.h Wed Jul 4 13:37:57 2007
@@ -25,19 +25,85 @@
#define IPC_TYPE_CONNECT 0x0001
-struct ipc_hdr {
- uint16_t id;
- uint16_t type;
- uint16_t seqnum;
- uint16_t length;
+#define IPC_SOCKET_NAME "\0/org/bluez/audio"
+
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX 108
+#endif
+
+/* Supported roles */
+#define PKT_ROLE_NONE 0
+#define PKT_ROLE_AUTO 1
+#define PKT_ROLE_VOICE 2
+#define PKT_ROLE_HIFI 3
+
+/* Packet types */
+#define PKT_TYPE_CFG_REQ 0
+#define PKT_TYPE_CFG_RSP 1
+#define PKT_TYPE_STATUS_REQ 2
+#define PKT_TYPE_STATUS_RSP 3
+#define PKT_TYPE_CTL_REQ 4
+#define PKT_TYPE_CTL_RSP 5
+#define PKT_TYPE_CTL_NTFY 6
+
+/* Errors codes */
+#define PKT_ERROR_NONE 0
+
+struct ipc_packet {
+ uint8_t id; /* Device id */
+ uint8_t role; /* Audio role eg: voice, wifi, auto... */
+ uint8_t type; /* Packet type */
+ uint8_t error; /* Packet error code */
+ uint8_t length; /* Payload length in bytes */
+ uint8_t data[0]; /* Packet payload */
} __attribute__ ((packed));
-struct ipc_connect_cmd {
- uint8_t src[6];
- uint8_t dst[6];
- uint16_t uuid;
+/* File descriptor options */
+#define CFG_FD_OPT_READ 0
+#define CFG_FD_OPT_WRITE 1
+#define CFG_FD_OPT_READWRITE 2
+
+struct ipc_data_cfg {
+ int fd; /* Stream file descriptor */
+ uint8_t fd_opt; /* Stream file descriptor options: read, write or readwrite*/
+ uint8_t encoding; /* Stream encoding */
+ uint8_t bitpool; /* Encoding bitpool */
+ uint8_t channels; /* Number of audio channel */
+ uint8_t pkt_len; /* Stream packet length */
+ uint8_t sample_size; /* Sample size in bytes */
+ uint16_t rate; /* Stream sample rate */
} __attribute__ ((packed));
-struct ipc_connect_evt {
- uint16_t id;
+/* Device status */
+#define STATUS_DISCONNECTED 0
+#define STATUS_CONNECTING 1
+#define STATUS_CONNECTED 2
+#define STATUS_STREAMING 3
+
+struct ipc_data_status {
+ uint8_t status; /* Stream status */
} __attribute__ ((packed));
+
+#define CTL_MODE_PLAYBACK 0
+#define CTL_MODE_CAPTURE 1
+#define CTL_MODE_GENERAL 2
+
+/* Supported control operations */
+#define CTL_KEY_POWER 0x40
+#define CTL_KEY_VOL_UP 0x41
+#define CTL_KEY_VOL_DOWN 0x42
+#define CTL_KEY_MUTE 0x43
+#define CTL_KEY_PLAY 0x44
+#define CTL_KEY_STOP 0x45
+#define CTL_KEY_PAUSE 0x46
+#define CTL_KEY_RECORD 0x47
+#define CTL_KEY_REWIND 0x48
+#define CTL_KEY_FAST_FORWARD 0x49
+#define CTL_KEY_EJECT 0x4A
+#define CTL_KEY_FORWARD 0x4B
+#define CTL_KEY_BACKWARD 0x4C
+
+struct ipc_data_ctl {
+ uint8_t mode; /* Control Mode */
+ uint8_t key; /* Control Key */
+} __attribute__ ((packed));
Modified: bluez-utils/branches/upstream/current/audio/main.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/main.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/main.c (original)
+++ bluez-utils/branches/upstream/current/audio/main.c Wed Jul 4 13:37:57 2007
@@ -37,13 +37,64 @@
#include "logging.h"
#include "manager.h"
-#include "headset.h"
+
+static gboolean disable_hfp = TRUE;
+static gboolean sco_hci = FALSE;
static GMainLoop *main_loop = NULL;
static void sig_term(int sig)
{
g_main_loop_quit(main_loop);
+}
+
+static void read_config(const char *file)
+{
+ GKeyFile *keyfile;
+ GError *err = NULL;
+ gboolean no_hfp;
+ char *sco_routing;
+
+ keyfile = g_key_file_new();
+
+ if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
+ error("Parsing %s failed: %s", file, err->message);
+ g_error_free(err);
+ g_key_file_free(keyfile);
+ return;
+ }
+
+ sco_routing = g_key_file_get_string(keyfile, "General",
+ "SCORouting", &err);
+ if (err) {
+ debug("%s: %s", file, err->message);
+ g_error_free(err);
+ err = NULL;
+ } else {
+ if (strcmp(sco_routing, "PCM") == 0)
+ sco_hci = FALSE;
+ else if (strcmp(sco_routing, "HCI") == 0)
+ sco_hci = TRUE;
+ else
+ error("Invalid Headset Routing value: %s",
+ sco_routing);
+ g_free(sco_routing);
+ }
+
+ no_hfp = g_key_file_get_boolean(keyfile, "Headset",
+ "DisableHFP", &err);
+ if (err) {
+ debug("%s: %s", file, err->message);
+ g_error_free(err);
+ err = NULL;
+ } else
+ disable_hfp = no_hfp;
+
+ debug("Config options: DisableHFP=%s, SCORouting=%s",
+ disable_hfp ? "true" : "false",
+ sco_hci ? "HCI" : "PCM");
+
+ g_key_file_free(keyfile);
}
int main(int argc, char *argv[])
@@ -65,6 +116,8 @@
enable_debug();
+ read_config(CONFIGDIR "/audio.conf");
+
main_loop = g_main_loop_new(NULL, FALSE);
conn = dbus_bus_system_setup_with_main_loop(NULL, NULL, NULL);
@@ -73,12 +126,17 @@
exit(1);
}
+ if (unix_init() < 0) {
+ error("Unable to setup unix socket");
+ exit(1);
+ }
+
if (audio_init(conn) < 0) {
error("Audio init failed!");
exit(1);
}
- if (headset_init(conn) < 0) {
+ if (gateway_init(conn, disable_hfp, sco_hci) < 0) {
error("Headset initialization failed!");
exit(1);
}
@@ -90,7 +148,9 @@
audio_exit();
- headset_exit();
+ gateway_exit();
+
+ unix_exit();
dbus_connection_unref(conn);
Modified: bluez-utils/branches/upstream/current/audio/manager.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/manager.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/manager.c (original)
+++ bluez-utils/branches/upstream/current/audio/manager.c Wed Jul 4 13:37:57 2007
@@ -26,175 +26,853 @@
#endif
#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <stdint.h>
#include <assert.h>
-#include <sys/socket.h>
-#include <sys/un.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <ctype.h>
#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
#include <bluetooth/rfcomm.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
#include <glib.h>
#include <dbus/dbus.h>
-#include "dbus.h"
#include "dbus-helper.h"
#include "logging.h"
-
-#include "ipc.h"
-#include "headset.h"
+#include "textfile.h"
#include "manager.h"
-
-#ifndef UNIX_PATH_MAX
-#define UNIX_PATH_MAX 108
-#endif
-
-#define SOCKET_NAME "/org/bluez/audio"
+#include "error.h"
+
+typedef enum {
+ HEADSET = 1 << 0,
+ GATEWAY = 1 << 1,
+ SINK = 1 << 2,
+ SOURCE = 1 << 3,
+ CONTROL = 1 << 4,
+ TARGET = 1 << 5,
+ INVALID = 1 << 6
+} audio_service_type;
+
+typedef enum {
+ GENERIC_AUDIO = 0,
+ ADVANCED_AUDIO,
+ AV_REMOTE,
+ GET_RECORDS
+} audio_sdp_state_t;
+
+struct audio_sdp_data {
+ struct device *device;
+
+ DBusMessage *msg; /* Method call or NULL */
+
+ GSList *handles; /* uint32_t * */
+ GSList *records; /* sdp_record_t * */
+
+ audio_sdp_state_t state;
+};
static DBusConnection *connection = NULL;
-static char *default_hs = NULL;
-
-static GSList *headsets = NULL;
-
-static int unix_sock = -1;
-
-/* FIXME: Remove these once global error functions exist */
-static DBusHandlerResult error_reply(DBusConnection *conn, DBusMessage *msg,
- const char *name, const char *descr)
-{
- DBusMessage *derr;
-
- if (!conn || !msg)
- return DBUS_HANDLER_RESULT_HANDLED;
-
- derr = dbus_message_new_error(msg, name, descr);
- if (!derr) {
- error("Unable to allocate new error return");
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
- }
-
- return send_message_and_unref(conn, derr);
-}
-
-static DBusHandlerResult err_invalid_args(DBusConnection *conn, DBusMessage *msg,
- const char *descr)
-{
- return error_reply(conn, msg, "org.bluez.audio.Error.InvalidArguments",
- descr ? descr : "Invalid arguments in method call");
-}
-
-static gboolean unix_event(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
- struct sockaddr_un addr;
- socklen_t addrlen;
- unsigned char buf[128];
- int sk, len;
-
- debug("chan %p cond %td data %p", chan, cond, data);
-
- if (cond & G_IO_NVAL)
- return FALSE;
-
- if (cond & (G_IO_HUP | G_IO_ERR)) {
- g_io_channel_close(chan);
- return FALSE;
- }
-
- sk = g_io_channel_unix_get_fd(chan);
-
- memset(&addr, 0, sizeof(addr));
- addrlen = sizeof(addr);
-
- len = recvfrom(sk, buf, sizeof(buf), 0, (struct sockaddr *) &addr, &addrlen);
-
- debug("path %s len %d", addr.sun_path + 1, len);
+static struct device *default_dev = NULL;
+
+static GSList *devices = NULL;
+
+static void get_next_record(struct audio_sdp_data *data);
+static DBusHandlerResult get_handles(const char *uuid,
+ struct audio_sdp_data *data);
+
+static struct device *find_device(bdaddr_t *bda)
+{
+ GSList *l;
+
+ for (l = devices; l != NULL; l = l->next) {
+ struct device *device = l->data;
+ if (bacmp(&device->dst, bda) == 0)
+ return device;
+ }
+
+ return NULL;
+}
+
+static struct device *create_device(bdaddr_t *bda)
+{
+ static int device_id = 0;
+ char path[128];
+
+ snprintf(path, sizeof(path) - 1,
+ "%s/device%d", AUDIO_MANAGER_PATH, device_id++);
+
+ return device_register(connection, path, bda);
+}
+
+static void remove_device(struct device *device)
+{
+ if (device == default_dev) {
+ debug("Removing default device");
+ default_dev = NULL;
+ }
+
+ devices = g_slist_remove(devices, device);
+
+ dbus_connection_destroy_object_path(connection, device->path);
+}
+
+static gboolean add_device(struct device *device)
+{
+ if (default_dev == NULL && g_slist_length(devices) == 0) {
+ debug("Selecting default device");
+ default_dev = device;
+ }
+
+ devices = g_slist_append(devices, device);
return TRUE;
}
-void manager_add_headset(const char *path)
-{
- char *my_path = g_strdup(path);
-
- headsets = g_slist_append(headsets, my_path);
+static uint16_t get_service_uuid(const sdp_record_t *record)
+{
+ sdp_list_t *classes;
+ uuid_t uuid;
+ uint16_t uuid16 = 0;
+
+ if (sdp_get_service_classes(record, &classes) < 0) {
+ error("Unable to get service classes from record");
+ return 0;
+ }
+
+ memcpy(&uuid, classes->data, sizeof(uuid));
+
+ if (!sdp_uuid128_to_uuid(&uuid)) {
+ error("Not a 16 bit UUID");
+ sdp_list_free(classes, free);
+ return 0;
+ }
+
+ if (uuid.type == SDP_UUID32) {
+ if (uuid.value.uuid32 > 0xFFFF) {
+ error("Not a 16 bit UUID");
+ goto done;
+ }
+ uuid16 = (uint16_t) uuid.value.uuid32;
+ } else
+ uuid16 = uuid.value.uuid16;
+
+done:
+ sdp_list_free(classes, free);
+
+ return uuid16;
+}
+
+static void handle_record(sdp_record_t *record, struct device *device)
+{
+ gboolean is_default;
+ uint16_t uuid16;
+
+ uuid16 = get_service_uuid(record);
+
+ switch (uuid16) {
+ case HEADSET_SVCLASS_ID:
+ debug("Found Headset record");
+ if (device->headset)
+ headset_update(device, record, uuid16);
+ else
+ device->headset = headset_init(device,
+ record, uuid16);
+ break;
+ case HEADSET_AGW_SVCLASS_ID:
+ debug("Found Headset AG record");
+ break;
+ case HANDSFREE_SVCLASS_ID:
+ debug("Found Hansfree record");
+ if (device->headset)
+ headset_update(device, record, uuid16);
+ else
+ device->headset = headset_init(device,
+ record, uuid16);
+ break;
+ case HANDSFREE_AGW_SVCLASS_ID:
+ debug("Found Handsfree AG record");
+ break;
+ case AUDIO_SINK_SVCLASS_ID:
+ debug("Found Audio Sink");
+ break;
+ case AUDIO_SOURCE_SVCLASS_ID:
+ debug("Found Audio Source");
+ break;
+ case AV_REMOTE_SVCLASS_ID:
+ debug("Found AV Remote");
+ break;
+ case AV_REMOTE_TARGET_SVCLASS_ID:
+ debug("Found AV Target");
+ break;
+ default:
+ debug("Unrecognized UUID: 0x%04X", uuid16);
+ break;
+ }
+
+ is_default = (default_dev == device) ? TRUE : FALSE;
+
+ device_store(device, is_default);
+}
+
+static gint record_iface_cmp(gconstpointer a, gconstpointer b)
+{
+ const sdp_record_t *record = a;
+ const char *interface = b;
+
+ switch (get_service_uuid(record)) {
+ case HEADSET_SVCLASS_ID:
+ case HANDSFREE_SVCLASS_ID:
+ return strcmp(interface, AUDIO_HEADSET_INTERFACE);
+
+ case HEADSET_AGW_SVCLASS_ID:
+ case HANDSFREE_AGW_SVCLASS_ID:
+ return strcmp(interface, AUDIO_GATEWAY_INTERFACE);
+
+ case AUDIO_SINK_SVCLASS_ID:
+ return strcmp(interface, AUDIO_SINK_INTERFACE);
+
+ case AUDIO_SOURCE_SVCLASS_ID:
+ return strcmp(interface, AUDIO_SOURCE_INTERFACE);
+
+ case AV_REMOTE_SVCLASS_ID:
+ return strcmp(interface, AUDIO_CONTROL_INTERFACE);
+
+ case AV_REMOTE_TARGET_SVCLASS_ID:
+ return strcmp(interface, AUDIO_TARGET_INTERFACE);
+
+ default:
+ return -1;
+ }
+}
+
+static void finish_sdp(struct audio_sdp_data *data, gboolean success)
+{
+ const char *addr;
+ char **required = NULL;
+ int required_len, i;
+ DBusMessage *reply = NULL;
+ DBusError derr;
+
+ debug("Audio service discovery completed with %s",
+ success ? "success" : "failure");
+
+ device_finish_sdp_transaction(data->device);
+
+ if (!success)
+ goto done;
+
+ if (!data->msg)
+ goto update;
+
+ dbus_error_init(&derr);
+ if (dbus_message_is_method_call(data->msg, AUDIO_MANAGER_INTERFACE,
+ "CreateHeadset")) {
+ dbus_message_get_args(data->msg, &derr,
+ DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_INVALID);
+ required = dbus_new0(char *, 2);
+ if (required == NULL) {
+ success = FALSE;
+ err_failed(connection, data->msg, "Out of memory");
+ goto done;
+ }
+
+ required[0] = dbus_new0(char,
+ strlen(AUDIO_HEADSET_INTERFACE) + 1);
+ if (required[0] == NULL) {
+ success = FALSE;
+ err_failed(connection, data->msg, "Out of memory");
+ goto done;
+ }
+
+ memcpy(required[0], AUDIO_HEADSET_INTERFACE,
+ strlen(AUDIO_HEADSET_INTERFACE) + 1);
+ required[1] = NULL;
+ required_len = 1;
+ }
+ else
+ dbus_message_get_args(data->msg, &derr,
+ DBUS_TYPE_STRING, &addr,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+ &required, &required_len,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_error_is_set(&derr)) {
+ error("Unable to get message args");
+ success = FALSE;
+ dbus_error_free(&derr);
+ goto done;
+ }
+
+ /* Return error if no audio related service records were found */
+ if (!data->records) {
+ debug("No audio audio related service records were found");
+ success = FALSE;
+ err_not_supported(connection, data->msg);
+ goto done;
+ }
+
+ for (i = 0; i < required_len; i++) {
+ const char *iface = required[i];
+
+ if (g_slist_find_custom(data->records, iface, record_iface_cmp))
+ continue;
+
+ debug("Required interface %s not supported", iface);
+ success = FALSE;
+ err_not_supported(connection, data->msg);
+ goto done;
+ }
+
+ reply = dbus_message_new_method_return(data->msg);
+ if (!reply) {
+ success = FALSE;
+ err_failed(connection, data->msg, "Out of memory");
+ goto done;
+ }
+
+ add_device(data->device);
+
+update:
+ g_slist_foreach(data->records, (GFunc) handle_record, data->device);
+
+ if (reply) {
+ dbus_connection_emit_signal(connection, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "DeviceCreated",
+ DBUS_TYPE_STRING,
+ &data->device->path,
+ DBUS_TYPE_INVALID);
+ if (data->device->headset)
+ dbus_connection_emit_signal(connection,
+ AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "HeadsetCreated",
+ DBUS_TYPE_STRING,
+ &data->device->path,
+ DBUS_TYPE_INVALID);
+ dbus_message_append_args(reply, DBUS_TYPE_STRING,
+ &data->device->path,
+ DBUS_TYPE_INVALID);
+ send_message_and_unref(connection, reply);
+ }
+
+done:
+ dbus_free_string_array(required);
+ if (!success)
+ remove_device(data->device);
+ if (data->msg)
+ dbus_message_unref(data->msg);
+ g_slist_foreach(data->handles, (GFunc) g_free, NULL);
+ g_slist_free(data->handles);
+ g_slist_foreach(data->records, (GFunc) sdp_record_free, NULL);
+ g_slist_free(data->records);
+ g_free(data);
+}
+
+static void get_record_reply(DBusPendingCall *call,
+ struct audio_sdp_data *data)
+{
+ DBusMessage *reply;
+ DBusError derr;
+ uint8_t *array;
+ int array_len, record_len;
+ sdp_record_t *record;
+
+ reply = dbus_pending_call_steal_reply(call);
+
+ dbus_error_init(&derr);
+ if (dbus_set_error_from_message(&derr, reply)) {
+ error("GetRemoteServiceRecord failed: %s", derr.message);
+ if (dbus_error_has_name(&derr,
+ "org.bluez.Error.ConnectionAttemptFailed"))
+ err_connect_failed(connection, data->msg,
+ strerror(EHOSTDOWN));
+ else
+ err_failed(connection, data->msg, derr.message);
+ dbus_error_free(&derr);
+ goto failed;
+ }
+
+ if (!dbus_message_get_args(reply, NULL,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &array, &array_len,
+ DBUS_TYPE_INVALID)) {
+ err_failed(connection, data->msg,
+ "Unable to get args from GetRecordReply");
+ goto failed;
+ }
+
+ record = sdp_extract_pdu(array, &record_len);
+ if (!record) {
+ error("Unable to extract service record from reply");
+ goto done;
+ }
+
+ if (record_len != array_len)
+ debug("warning: array len (%d) != record len (%d)",
+ array_len, record_len);
+
+ data->records = g_slist_append(data->records, record);
+
+done:
+ dbus_message_unref(reply);
+
+ if (data->handles)
+ get_next_record(data);
+ else
+ finish_sdp(data, TRUE);
+
+ return;
+
+failed:
+ if (reply)
+ dbus_message_unref(reply);
+ finish_sdp(data, FALSE);
+}
+
+static void get_next_record(struct audio_sdp_data *data)
+{
+ DBusMessage *msg;
+ DBusPendingCall *pending;
+ char address[18], *ptr = address;
+ dbus_uint32_t *handle;
+
+ msg = dbus_message_new_method_call("org.bluez",
+ data->device->adapter_path,
+ "org.bluez.Adapter",
+ "GetRemoteServiceRecord");
+ if (!msg) {
+ error("Unable to allocate new method call");
+ err_connect_failed(connection, data->msg, strerror(ENOMEM));
+ finish_sdp(data, FALSE);
+ return;
+ }
+
+ handle = data->handles->data;
+
+ data->handles = g_slist_remove(data->handles, data->handles->data);
+
+ ba2str(&data->device->dst, address);
+
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &ptr,
+ DBUS_TYPE_UINT32, handle,
+ DBUS_TYPE_INVALID);
+
+ g_free(handle);
+
+ if (!dbus_connection_send_with_reply(connection, msg, &pending, -1)) {
+ error("Sending GetRemoteServiceRecord failed");
+ err_connect_failed(connection, data->msg, strerror(EIO));
+ finish_sdp(data, FALSE);
+ return;
+ }
+
+ dbus_pending_call_set_notify(pending,
+ (DBusPendingCallNotifyFunction) get_record_reply,
+ data, NULL);
+ dbus_pending_call_unref(pending);
+ dbus_message_unref(msg);
+}
+
+static GSList *find_handle(GSList *handles, dbus_uint32_t handle)
+{
+ while (handles) {
+ if (*(dbus_uint32_t *) handles->data == handle)
+ return handles;
+ handles = handles->next;
+ }
+
+ return NULL;
+}
+
+static void get_handles_reply(DBusPendingCall *call,
+ struct audio_sdp_data *data)
+{
+ DBusMessage *reply;
+ DBusError derr;
+ dbus_uint32_t *array = NULL;
+ int array_len, i;
+
+ reply = dbus_pending_call_steal_reply(call);
+
+ dbus_error_init(&derr);
+ if (dbus_set_error_from_message(&derr, reply)) {
+ error("GetRemoteServiceHandles failed: %s", derr.message);
+ if (dbus_error_has_name(&derr,
+ "org.bluez.Error.ConnectionAttemptFailed"))
+ err_connect_failed(connection, data->msg, strerror(EHOSTDOWN));
+ else
+ err_failed(connection, data->msg, derr.message);
+ dbus_error_free(&derr);
+ goto failed;
+ }
+
+ if (!dbus_message_get_args(reply, NULL,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32,
+ &array, &array_len,
+ DBUS_TYPE_INVALID)) {
+ err_failed(connection, data->msg,
+ "Unable to get args from reply");
+ goto failed;
+ }
+
+ for (i = 0; i < array_len; i++) {
+ if (!find_handle(data->handles, array[i])) {
+ dbus_uint32_t *handle = g_new(dbus_uint32_t, 1);
+ *handle = array[i];
+ data->handles = g_slist_append(data->handles, handle);
+ }
+ }
+
+ data->state++;
+
+ switch (data->state) {
+ case ADVANCED_AUDIO:
+ get_handles(ADVANCED_AUDIO_UUID, data);
+ break;
+ case AV_REMOTE:
+ get_handles(AVRCP_REMOTE_UUID, data);
+ break;
+ default:
+ if (data->handles)
+ get_next_record(data);
+ else
+ finish_sdp(data, TRUE);
+ }
+
+ dbus_message_unref(reply);
+
+ return;
+
+failed:
+ dbus_message_unref(reply);
+ finish_sdp(data, FALSE);
+}
+
+static DBusHandlerResult get_handles(const char *uuid,
+ struct audio_sdp_data *data)
+{
+ DBusPendingCall *pending;
+ char address[18];
+ const char *ptr = address;
+ DBusMessage *msg;
+
+ msg = dbus_message_new_method_call("org.bluez",
+ data->device->adapter_path,
+ "org.bluez.Adapter",
+ "GetRemoteServiceHandles");
+ if (!msg) {
+ err_failed(connection, data->msg,
+ "Could not create a new dbus message");
+ goto failed;
+ }
+
+ ba2str(&data->device->dst, address);
+
+ dbus_message_append_args(msg, DBUS_TYPE_STRING, &ptr,
+ DBUS_TYPE_STRING, &uuid,
+ DBUS_TYPE_INVALID);
+
+ if (!dbus_connection_send_with_reply(connection, msg, &pending, -1)) {
+ err_failed(connection, data->msg,
+ "Sending GetRemoteServiceHandles failed");
+ goto failed;
+ }
+
+ dbus_pending_call_set_notify(pending,
+ (DBusPendingCallNotifyFunction) get_handles_reply,
+ data, NULL);
+ dbus_pending_call_unref(pending);
+ dbus_message_unref(msg);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+failed:
+ if (msg)
+ dbus_message_unref(msg);
+ finish_sdp(data, FALSE);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult resolve_services(DBusMessage *msg,
+ struct device *device)
+{
+ struct audio_sdp_data *sdp_data;
+
+ sdp_data = g_new0(struct audio_sdp_data, 1);
+ if (msg)
+ sdp_data->msg = dbus_message_ref(msg);
+ sdp_data->device = device;
+
+ return get_handles(GENERIC_AUDIO_UUID, sdp_data);
+}
+
+struct device *manager_device_connected(bdaddr_t *bda)
+{
+ struct device *device;
+ const char *path;
+ gboolean created = FALSE;
+
+ device = find_device(bda);
+ if (device && device->headset)
+ return device;
+
+ if (!device) {
+ device = create_device(bda);
+ if (!add_device(device)) {
+ remove_device(device);
+ return NULL;
+ }
+ created = TRUE;
+ }
+
+ if (!device->headset)
+ device->headset = headset_init(device, NULL, 0);
+
+ if (!device->headset)
+ return NULL;
+
+ path = device->path;
+
+ if (created) {
+ dbus_connection_emit_signal(connection, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "DeviceCreated",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+ resolve_services(NULL, device);
+ }
dbus_connection_emit_signal(connection, AUDIO_MANAGER_PATH,
AUDIO_MANAGER_INTERFACE,
"HeadsetCreated",
- DBUS_TYPE_STRING, &my_path,
- DBUS_TYPE_INVALID);
-
- if (!default_hs) {
- default_hs = my_path;
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ if (!default_dev) {
+ default_dev = device;
dbus_connection_emit_signal(connection, AUDIO_MANAGER_PATH,
AUDIO_MANAGER_INTERFACE,
"DefaultHeadsetChanged",
- DBUS_TYPE_STRING, &my_path,
+ DBUS_TYPE_STRING, &path,
DBUS_TYPE_INVALID);
}
-}
-
-static void manager_remove_headset(char *path)
-{
- headset_remove(path);
- g_free(path);
-}
-
-static DBusHandlerResult am_create_headset(DBusConnection *conn, DBusMessage *msg,
+
+ return device;
+}
+
+static gboolean device_supports_interface(struct device *device,
+ const char *iface)
+{
+ if (strcmp(iface, AUDIO_HEADSET_INTERFACE) == 0)
+ return device->headset ? TRUE : FALSE;
+
+ if (strcmp(iface, AUDIO_GATEWAY_INTERFACE) == 0)
+ return device->gateway ? TRUE : FALSE;
+
+ if (strcmp(iface, AUDIO_SOURCE_INTERFACE) == 0)
+ return device->source ? TRUE : FALSE;
+
+ if (strcmp(iface, AUDIO_SINK_INTERFACE) == 0)
+ return device->sink ? TRUE : FALSE;
+
+ if (strcmp(iface, AUDIO_CONTROL_INTERFACE) == 0)
+ return device->control ? TRUE : FALSE;
+
+ if (strcmp(iface, AUDIO_TARGET_INTERFACE) == 0)
+ return device->target ? TRUE : FALSE;
+
+ debug("Unknown interface %s", iface);
+
+ return FALSE;
+}
+
+static gboolean device_matches(struct device *device, char **interfaces)
+{
+ int i;
+
+ for (i = 0; interfaces[i]; i++) {
+ if (device_supports_interface(device, interfaces[i]))
+ continue;
+ debug("Device does not support interface %s", interfaces[i]);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static DBusHandlerResult am_create_device(DBusConnection *conn,
+ DBusMessage *msg,
void *data)
{
- const char *hs_path;
- const char *address;
+ const char *address, *path;
+ char **required;
+ int required_len;
bdaddr_t bda;
+ struct device *device;
DBusMessage *reply;
DBusError derr;
dbus_error_init(&derr);
- if (!dbus_message_get_args(msg, &derr,
+ if (dbus_message_is_method_call(msg, AUDIO_MANAGER_INTERFACE,
+ "CreateHeadset")) {
+ dbus_message_get_args(msg, &derr,
DBUS_TYPE_STRING, &address,
- DBUS_TYPE_INVALID)) {
- err_invalid_args(connection, msg, derr.message);
- return DBUS_HANDLER_RESULT_HANDLED;
- }
+ DBUS_TYPE_INVALID);
+ required = dbus_new0(char *, 2);
+ if (required == NULL)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ required[0] = dbus_new0(char,
+ strlen(AUDIO_HEADSET_INTERFACE) + 1);
+ if (required[0] == NULL) {
+ dbus_free(required);
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ memcpy(required[0], AUDIO_HEADSET_INTERFACE,
+ strlen(AUDIO_HEADSET_INTERFACE) + 1);
+ required[1] = NULL;
+ required_len = 1;
+ }
+ else
+ dbus_message_get_args(msg, &derr,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+ &required, &required_len,
+ DBUS_TYPE_INVALID);
+
if (dbus_error_is_set(&derr)) {
err_invalid_args(connection, msg, derr.message);
dbus_error_free(&derr);
return DBUS_HANDLER_RESULT_HANDLED;
}
+ str2ba(address, &bda);
+
+ device = find_device(&bda);
+ if (!device) {
+ device = create_device(&bda);
+ dbus_free_string_array(required);
+ return resolve_services(msg, device);
+ }
+
+ if (!device_matches(device, required)) {
+ dbus_free_string_array(required);
+ return err_not_supported(conn, msg);
+ }
+
+ dbus_free_string_array(required);
+
+ path = device->path;
+
reply = dbus_message_new_method_return(msg);
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- str2ba(address, &bda);
-
- hs_path = headset_get(&bda);
- if (!hs_path) {
- hs_path = headset_add(&bda);
- if (!hs_path)
- return error_reply(connection, msg,
- "org.bluez.audio.Error.Failed",
- "Unable to create new headset object");
- manager_add_headset(hs_path);
- }
-
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &hs_path,
- DBUS_TYPE_INVALID);
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ return send_message_and_unref(conn, reply);
+}
+
+static DBusHandlerResult am_list_devices(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ DBusMessageIter iter, array_iter;
+ DBusMessage *reply;
+ DBusError derr;
+ GSList *l;
+ char **required;
+ int required_len;
+
+ dbus_error_init(&derr);
+
+ if (dbus_message_is_method_call(msg, AUDIO_MANAGER_INTERFACE,
+ "ListHeadsets")) {
+ required = dbus_new0(char *, 2);
+ if (required == NULL)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ required[0] = dbus_new0(char,
+ strlen(AUDIO_HEADSET_INTERFACE) + 1);
+ if (required[0] == NULL) {
+ dbus_free(required);
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ }
+
+ memcpy(required[0], AUDIO_HEADSET_INTERFACE,
+ strlen(AUDIO_HEADSET_INTERFACE) + 1);
+ required[1] = NULL;
+ required_len = 1;
+ }
+ else
+ dbus_message_get_args(msg, &derr,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+ &required, &required_len,
+ DBUS_TYPE_INVALID);
+
+ if (dbus_error_is_set(&derr)) {
+ err_invalid_args(connection, msg, derr.message);
+ dbus_error_free(&derr);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+
+ for (l = devices; l != NULL; l = l->next) {
+ struct device *device = l->data;
+
+ if (!device_matches(device, required))
+ continue;
+
+ dbus_message_iter_append_basic(&array_iter,
+ DBUS_TYPE_STRING, &device->path);
+ }
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ dbus_free_string_array(required);
return send_message_and_unref(connection, reply);
}
-static DBusHandlerResult am_remove_headset(DBusConnection *conn, DBusMessage *msg,
+static gint device_path_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct device *device = a;
+ const char *path = b;
+
+ return strcmp(device->path, path);
+}
+
+static DBusHandlerResult am_remove_device(DBusConnection *conn,
+ DBusMessage *msg,
void *data)
{
DBusError derr;
DBusMessage *reply;
GSList *match;
- char *path;
+ const char *path;
+ struct device *device;
dbus_error_init(&derr);
if (!dbus_message_get_args(msg, &derr,
@@ -209,29 +887,32 @@
return DBUS_HANDLER_RESULT_HANDLED;
}
- match = g_slist_find_custom(headsets, path, (GCompareFunc) strcmp);
+ match = g_slist_find_custom(devices, path, device_path_cmp);
if (!match)
- return error_reply(connection, msg,
- "org.bluez.audio.Error.DoesNotExist",
- "The headset does not exist");
+ return err_does_not_exist(connection, msg);
reply = dbus_message_new_method_return(msg);
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- path = match->data;
-
- headsets = g_slist_remove(headsets, path);
-
- if (default_hs == path) {
+ device = match->data;
+
+ remove_device(device);
+
+ if (default_dev == device) {
const char *param;
-
- if (!headsets)
- default_hs = NULL;
- else
- default_hs = headsets->data;
-
- param = default_hs ? default_hs : "";
+ GSList *l;
+
+ default_dev = NULL;
+
+ for (l = devices; l != NULL; l = l->next) {
+ device = l->data;
+
+ if (device->headset)
+ default_dev = device;
+ }
+
+ param = default_dev ? default_dev->path : "";
dbus_connection_emit_signal(conn, AUDIO_MANAGER_PATH,
AUDIO_MANAGER_INTERFACE,
@@ -246,66 +927,85 @@
DBUS_TYPE_STRING, &path,
DBUS_TYPE_INVALID);
- headset_remove(path);
-
- g_free(path);
+ dbus_connection_emit_signal(conn, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "DeviceRemoved",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
return send_message_and_unref(connection, reply);
}
-static DBusHandlerResult am_list_headsets(DBusConnection *conn, DBusMessage *msg,
+static DBusHandlerResult am_find_by_addr(DBusConnection *conn,
+ DBusMessage *msg,
void *data)
{
- DBusMessageIter iter;
- DBusMessageIter array_iter;
+ const char *address;
DBusMessage *reply;
- GSList *l;
+ DBusError derr;
+ struct device *device;
+ bdaddr_t bda;
+
+ dbus_error_init(&derr);
+ dbus_message_get_args(msg, &derr,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID);
+ if (dbus_error_is_set(&derr)) {
+ err_invalid_args(connection, msg, derr.message);
+ dbus_error_free(&derr);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ str2ba(address, &bda);
+
+ device = find_device(&bda);
+
+ if (!device)
+ return err_does_not_exist(conn, msg);
reply = dbus_message_new_method_return(msg);
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- dbus_message_iter_init_append(reply, &iter);
-
- dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_STRING_AS_STRING, &array_iter);
-
- for (l = headsets; l != NULL; l = l->next)
- dbus_message_iter_append_basic(&array_iter,
- DBUS_TYPE_STRING, &l->data);
-
- dbus_message_iter_close_container(&iter, &array_iter);
-
- return send_message_and_unref(connection, reply);
-}
-
-static DBusHandlerResult am_get_default_headset(DBusConnection *conn, DBusMessage *msg,
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &device->path,
+ DBUS_TYPE_INVALID);
+
+ return send_message_and_unref(conn, reply);
+}
+
+static DBusHandlerResult am_default_device(DBusConnection *conn,
+ DBusMessage *msg,
void *data)
{
DBusMessage *reply;
- if (!default_hs)
- return error_reply(connection, msg,
- "org.bluez.audio.Error.DoesNotExist",
- "There is no default headset");
+ if (!default_dev)
+ return err_does_not_exist(connection, msg);
+
+ if (default_dev->headset == NULL &&
+ dbus_message_is_method_call(msg, AUDIO_MANAGER_INTERFACE,
+ "DefaultHeadset"))
+ return err_does_not_exist(connection, msg);
reply = dbus_message_new_method_return(msg);
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_hs,
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_dev->path,
DBUS_TYPE_INVALID);
return send_message_and_unref(connection, reply);
}
-static DBusHandlerResult am_change_default_headset(DBusConnection *conn, DBusMessage *msg,
+static DBusHandlerResult am_change_default_device(DBusConnection *conn,
+ DBusMessage *msg,
void *data)
{
DBusError derr;
DBusMessage *reply;
GSList *match;
const char *path;
+ struct device *device;
dbus_error_init(&derr);
if (!dbus_message_get_args(msg, &derr,
@@ -320,85 +1020,158 @@
return DBUS_HANDLER_RESULT_HANDLED;
}
- match = g_slist_find_custom(headsets, path, (GCompareFunc) strcmp);
+ match = g_slist_find_custom(devices, path, device_path_cmp);
if (!match)
- return error_reply(connection, msg,
- "org.bluez.audio.Error.DoesNotExist",
- "The headset does not exist");
+ return err_does_not_exist(connection, msg);
reply = dbus_message_new_method_return(msg);
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- default_hs = match->data;
-
- dbus_connection_emit_signal(conn, AUDIO_MANAGER_PATH,
- AUDIO_MANAGER_INTERFACE,
- "DefaultHeadsetChanged",
- DBUS_TYPE_STRING, &default_hs,
- DBUS_TYPE_INVALID);
-
+ device = match->data;
+
+ if (!dbus_message_is_method_call(msg, AUDIO_MANAGER_INTERFACE,
+ "ChangeDefaultHeadset"))
+ dbus_connection_emit_signal(conn, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "DefaultDeviceChanged",
+ DBUS_TYPE_STRING, &device->path,
+ DBUS_TYPE_INVALID);
+ else if (device->headset)
+ dbus_connection_emit_signal(conn, AUDIO_MANAGER_PATH,
+ AUDIO_MANAGER_INTERFACE,
+ "DefaultHeadsetChanged",
+ DBUS_TYPE_STRING, &device->path,
+ DBUS_TYPE_INVALID);
+ else
+ return err_does_not_exist(connection, msg);
+
+ default_dev = device;
+ device_store(device, TRUE);
return send_message_and_unref(connection, reply);
}
static DBusMethodVTable manager_methods[] = {
- { "CreateHeadset", am_create_headset,
- "s", "s" },
- { "RemoveHeadset", am_remove_headset,
- "s", "" },
- { "ListHeadsets", am_list_headsets,
- "", "as" },
- { "DefaultHeadset", am_get_default_headset,
- "", "s" },
- { "ChangeDefaultHeadset", am_change_default_headset,
- "s", "" },
+ { "CreateDevice", am_create_device,
+ "sas", "s" },
+ { "RemoveDevice", am_remove_device,
+ "s", "" },
+ { "ListDevices", am_list_devices,
+ "as", "as" },
+ { "DefaultDevice", am_default_device,
+ "", "s" },
+ { "ChangeDefaultDevice", am_change_default_device,
+ "s", "" },
+ { "CreateHeadset", am_create_device,
+ "s", "s" },
+ { "RemoveHeadset", am_remove_device,
+ "s", "" },
+ { "ListHeadsets", am_list_devices,
+ "", "as" },
+ { "FindDeviceByAddress", am_find_by_addr,
+ "s", "s" },
+ { "DefaultHeadset", am_default_device,
+ "", "s" },
+ { "ChangeDefaultHeadset", am_change_default_device,
+ "s", "" },
{ NULL, NULL, NULL, NULL },
};
static DBusSignalVTable manager_signals[] = {
+ { "DeviceCreated", "s" },
+ { "DeviceRemoved", "s" },
{ "HeadsetCreated", "s" },
{ "HeadsetRemoved", "s" },
+ { "DefaultDeviceChanged", "s" },
{ "DefaultHeadsetChanged", "s" },
{ NULL, NULL }
};
+static void parse_stored_devices(char *key, char *value, void *data)
+{
+ struct device *device;
+ bdaddr_t dst;
+
+ if (!key || !value || strcmp(key, "default") == 0)
+ return;
+
+ info("Loading device %s (%s)", key, value);
+ str2ba(key, &dst);
+
+ device = create_device(&dst);
+ if (!device)
+ return;
+
+ if (strcmp(value, "headset") == 0)
+ device->headset = headset_init(device, NULL, 0);
+
+ add_device(device);
+}
+
+static void register_devices_stored(const char *adapter)
+{
+ char filename[PATH_MAX + 1];
+ struct stat st;
+ struct device *device;
+ bdaddr_t src;
+ bdaddr_t dst;
+ char *addr;
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter, "audio");
+
+ str2ba(adapter, &src);
+
+ if (stat(filename, &st) < 0)
+ return;
+
+ if (!(st.st_mode & __S_IFREG))
+ return;
+
+ textfile_foreach(filename, parse_stored_devices, &src);
+
+ addr = textfile_get(filename, "default");
+ if (!addr)
+ return;
+
+ str2ba(addr, &dst);
+ device = find_device(&dst);
+
+ if (device) {
+ info("Setting %s as default device", addr);
+ default_dev = device;
+ }
+
+ free(addr);
+}
+
+static void register_stored(void)
+{
+ char dirname[PATH_MAX + 1];
+ struct dirent *de;
+ DIR *dir;
+
+ snprintf(dirname, PATH_MAX, "%s", STORAGEDIR);
+
+ dir = opendir(dirname);
+ if (!dir)
+ return;
+
+ while ((de = readdir(dir)) != NULL) {
+ if (!isdigit(de->d_name[0]))
+ continue;
+
+ /* Device objects */
+ register_devices_stored(de->d_name);
+ }
+
+ closedir(dir);
+}
+
int audio_init(DBusConnection *conn)
{
- GIOChannel *io;
- struct sockaddr_un addr;
- int sk;
-
- sk = socket(PF_LOCAL, SOCK_DGRAM, 0);
- if (sk < 0) {
- error("Can't create unix socket: %s (%d)", strerror(errno), errno);
- return -1;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s", SOCKET_NAME);
-
- if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- error("Can't bind unix socket: %s (%d)", strerror(errno), errno);
- close(sk);
- return -1;
- }
-
- set_nonblocking(sk);
-
- unix_sock = sk;
-
- io = g_io_channel_unix_new(sk);
-
- g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- unix_event, NULL);
-
- g_io_channel_unref(io);
-
if (!dbus_connection_create_object_path(conn, AUDIO_MANAGER_PATH,
NULL, NULL)) {
error("D-Bus failed to register %s path", AUDIO_MANAGER_PATH);
- close(sk);
return -1;
}
@@ -410,28 +1183,30 @@
AUDIO_MANAGER_INTERFACE, AUDIO_MANAGER_PATH);
dbus_connection_destroy_object_path(conn,
AUDIO_MANAGER_PATH);
- close(sk);
return -1;
}
connection = dbus_connection_ref(conn);
+ info("Registered manager path:%s", AUDIO_MANAGER_PATH);
+
+ register_stored();
+
return 0;
}
void audio_exit(void)
{
- close(unix_sock);
-
- unix_sock = -1;
-
- if (headsets) {
- g_slist_foreach(headsets, (GFunc) manager_remove_headset, NULL);
- g_slist_free(headsets);
- headsets = NULL;
- }
+ g_slist_foreach(devices, (GFunc) remove_device, NULL);
+ g_slist_free(devices);
+ devices = NULL;
dbus_connection_unref(connection);
connection = NULL;
}
+
+struct device *manager_default_device()
+{
+ return default_dev;
+}
Modified: bluez-utils/branches/upstream/current/audio/manager.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/manager.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/manager.h (original)
+++ bluez-utils/branches/upstream/current/audio/manager.h Wed Jul 4 13:37:57 2007
@@ -21,19 +21,18 @@
*
*/
-#include <bluetooth/bluetooth.h>
-
#include <dbus/dbus.h>
-#include "headset.h"
+#include "device.h"
+#define MAX_PATH_LENGTH 64 /* D-Bus path */
#define AUDIO_MANAGER_PATH "/org/bluez/audio"
#define AUDIO_MANAGER_INTERFACE "org.bluez.audio.Manager"
-
-#define HEADSET_PATH_BASE AUDIO_MANAGER_PATH "/headset"
-
-void manager_add_headset(const char *path);
int audio_init(DBusConnection *conn);
void audio_exit(void);
+
+struct device *manager_device_connected(bdaddr_t *bda);
+
+struct device *manager_default_device();
Modified: bluez-utils/branches/upstream/current/audio/pcm_bluetooth.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/pcm_bluetooth.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/audio/pcm_bluetooth.c (original)
+++ bluez-utils/branches/upstream/current/audio/pcm_bluetooth.c Wed Jul 4 13:37:57 2007
@@ -31,32 +31,44 @@
#include <alsa/asoundlib.h>
#include <alsa/pcm_external.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sco.h>
+
#include "ipc.h"
-#ifndef UNIX_PATH_MAX
-#define UNIX_PATH_MAX 108
+#ifdef ENABLE_DEBUG
+#define DBG(fmt, arg...) printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
+#else
+#define DBG(fmt, arg...)
#endif
-#define DBG(fmt, arg...) printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
-
-#define SOCKET_NAME "/org/bluez/audio"
+#ifndef SCO_TXBUFS
+#define SCO_TXBUFS 0x03
+#endif
+
+#ifndef SCO_RXBUFS
+#define SCO_RXBUFS 0x04
+#endif
struct bluetooth_data {
snd_pcm_ioplug_t io;
snd_pcm_sframes_t hw_ptr;
- int sock;
+ struct ipc_data_cfg cfg; /* Bluetooth device config */
+ int sock; /* Daemon unix socket */
+ uint8_t *buffer; /* Transfer buffer */
+ uint8_t count; /* Transfer buffer counter */
};
static int bluetooth_start(snd_pcm_ioplug_t *io)
{
- DBG("io %p", io);
+ DBG("bluetooth_start %p", io);
return 0;
}
static int bluetooth_stop(snd_pcm_ioplug_t *io)
{
- DBG("io %p", io);
+ DBG("bluetooth_stop %p", io);
return 0;
}
@@ -65,22 +77,196 @@
{
struct bluetooth_data *data = io->private_data;
- //DBG("io %p", io);
-
- //DBG("hw_ptr=%lu", data->hw_ptr);
+ DBG("bluetooth_pointer %p", io);
+
+ DBG("hw_ptr=%lu", data->hw_ptr);
return data->hw_ptr;
}
+static void bluetooth_exit(struct bluetooth_data *data)
+{
+ if (data == NULL)
+ return;
+
+ if (data->sock >= 0)
+ close(data->sock);
+
+ if (data->buffer)
+ free(data->buffer);
+
+ free(data);
+}
+
static int bluetooth_close(snd_pcm_ioplug_t *io)
{
struct bluetooth_data *data = io->private_data;
- DBG("io %p", io);
-
- free(data);
-
- return 0;
+ DBG("bluetooth_close %p", io);
+
+ bluetooth_exit(data);
+
+ return 0;
+}
+
+static int bluetooth_prepare(snd_pcm_ioplug_t *io)
+{
+ struct bluetooth_data *data = io->private_data;
+
+ DBG("Preparing with io->period_size = %lu, io->buffer_size = %lu",
+ io->period_size, io->buffer_size);
+
+ if (io->stream == SND_PCM_STREAM_PLAYBACK)
+ /* If not null for playback, xmms doesn't display time
+ * correctly */
+ data->hw_ptr = 0;
+ else
+ /* ALSA library is really picky on the fact hw_ptr is not null.
+ * If it is, capture won't start */
+ data->hw_ptr = io->period_size;
+
+ return 0;
+}
+
+static int bluetooth_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params)
+{
+ struct bluetooth_data *data = io->private_data;
+ struct ipc_data_cfg cfg = data->cfg;
+ uint32_t period_count = io->buffer_size / io->period_size;
+ int opt_name, err;
+
+ DBG("fd = %d, period_count = %d", cfg.fd, period_count);
+
+ opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
+ SCO_TXBUFS : SCO_RXBUFS;
+
+ if (setsockopt(cfg.fd, SOL_SCO, opt_name, &period_count,
+ sizeof(period_count)) == 0)
+ return 0;
+
+ opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
+ SO_SNDBUF : SO_RCVBUF;
+
+ if (setsockopt(cfg.fd, SOL_SCO, opt_name, &period_count,
+ sizeof(period_count)) == 0)
+ return 0;
+
+ err = errno;
+ SNDERR("%s (%d)", strerror(err), err);
+
+ return -err;
+}
+
+static snd_pcm_sframes_t bluetooth_read(snd_pcm_ioplug_t *io,
+ const snd_pcm_channel_area_t *areas,
+ snd_pcm_uframes_t offset,
+ snd_pcm_uframes_t size)
+{
+ struct bluetooth_data *data = io->private_data;
+ struct ipc_data_cfg cfg = data->cfg;
+ snd_pcm_uframes_t frames_to_write, ret;
+ unsigned char *buff;
+ int nrecv, frame_size = 0;
+
+ DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu, io->nonblock=%u",
+ areas->step, areas->first, offset, size, io->nonblock);
+
+ if (data->count > 0)
+ goto proceed;
+
+ frame_size = areas->step / 8;
+
+ nrecv = recv(cfg.fd, data->buffer, cfg.pkt_len,
+ MSG_WAITALL | (io->nonblock ? MSG_DONTWAIT : 0));
+
+ if (nrecv < 0) {
+ ret = (errno == EPIPE) ? -EIO : -errno;
+ goto done;
+ }
+
+ if (nrecv != cfg.pkt_len) {
+ ret = -EIO;
+ SNDERR(strerror(-ret));
+ goto done;
+ }
+
+ /* Increment hardware transmition pointer */
+ data->hw_ptr = (data->hw_ptr + cfg.pkt_len / cfg.sample_size) % io->buffer_size;
+
+proceed:
+ buff = (unsigned char *) areas->addr + (areas->first + areas->step * offset) / 8;
+
+ if ((data->count + cfg.sample_size * size) <= cfg.pkt_len)
+ frames_to_write = size;
+ else
+ frames_to_write = (cfg.pkt_len - data->count) / frame_size;
+
+ memcpy(buff, data->buffer + data->count, frame_size * frames_to_write);
+ data->count += (frame_size * frames_to_write);
+ data->count %= cfg.pkt_len;
+
+ /* Return written frames count */
+ ret = frames_to_write;
+
+done:
+ DBG("returning %lu", ret);
+ return ret;
+}
+
+static snd_pcm_sframes_t bluetooth_write(snd_pcm_ioplug_t *io,
+ const snd_pcm_channel_area_t *areas,
+ snd_pcm_uframes_t offset,
+ snd_pcm_uframes_t size)
+{
+ struct bluetooth_data *data = io->private_data;
+ struct ipc_data_cfg cfg = data->cfg;
+ snd_pcm_sframes_t ret = 0;
+ snd_pcm_uframes_t frames_to_read;
+ uint8_t *buff;
+ int rsend, frame_size;
+
+ DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu,"
+ "io->nonblock=%u", areas->step, areas->first,
+ offset, size, io->nonblock);
+
+ frame_size = areas->step / 8;
+ if ((data->count + size * frame_size) <= cfg.pkt_len)
+ frames_to_read = size;
+ else
+ frames_to_read = (cfg.pkt_len - data->count) / frame_size;
+
+ DBG("count = %d, frames_to_read = %lu", data->count, frames_to_read);
+
+ /* Ready for more data */
+ buff = (uint8_t *) areas->addr + (areas->first + areas->step * offset) / 8;
+ memcpy(data->buffer + data->count, buff, frame_size * frames_to_read);
+
+ if ((data->count + frames_to_read * frame_size) != cfg.pkt_len) {
+ /* Remember we have some frame in the pipe now */
+ data->count += frames_to_read * frame_size;
+ ret = frames_to_read;
+ goto done;
+ }
+
+ rsend = send(cfg.fd, data->buffer, cfg.pkt_len,
+ io->nonblock ? MSG_DONTWAIT : 0);
+ if (rsend > 0) {
+ /* Reset count pointer */
+ data->count = 0;
+
+ /* Increment hardware transmition pointer */
+ data->hw_ptr = (data->hw_ptr + cfg.pkt_len / frame_size)
+ % io->buffer_size;
+
+ ret = frames_to_read;
+ } else if (rsend < 0)
+ ret = (errno == EPIPE) ? -EIO : -errno;
+ else
+ ret = -EIO;
+
+done:
+ DBG("returning %d", (int)ret);
+ return ret;
}
static snd_pcm_ioplug_callback_t bluetooth_playback_callback = {
@@ -88,11 +274,9 @@
.stop = bluetooth_stop,
.pointer = bluetooth_pointer,
.close = bluetooth_close,
-#if 0
.hw_params = bluetooth_hw_params,
.prepare = bluetooth_prepare,
.transfer = bluetooth_write,
-#endif
};
static snd_pcm_ioplug_callback_t bluetooth_capture_callback = {
@@ -100,17 +284,17 @@
.stop = bluetooth_stop,
.pointer = bluetooth_pointer,
.close = bluetooth_close,
-#if 0
.hw_params = bluetooth_hw_params,
.prepare = bluetooth_prepare,
.transfer = bluetooth_read,
-#endif
};
#define ARRAY_NELEMS(a) (sizeof((a)) / sizeof((a)[0]))
static int bluetooth_hw_constraint(snd_pcm_ioplug_t *io)
{
+ struct bluetooth_data *data = io->private_data;
+ struct ipc_data_cfg cfg = data->cfg;
snd_pcm_access_t access_list[] = {
SND_PCM_ACCESS_RW_INTERLEAVED,
/* Mmap access is really useless fo this driver, but we
@@ -123,30 +307,215 @@
};
int err;
+ /* access type */
err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
ARRAY_NELEMS(access_list), access_list);
if (err < 0)
return err;
+ /* supported formats */
err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
ARRAY_NELEMS(format_list), format_list);
if (err < 0)
return err;
- err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS, 1, 1);
- if (err < 0)
- return err;
-
- err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, 8000, 8000);
- if (err < 0)
- return err;
-
- err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, 48, 48);
- if (err < 0)
- return err;
-
- err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 2, 200);
- if (err < 0)
+ /* supported channels */
+ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS,
+ cfg.channels, cfg.channels);
+ if (err < 0)
+ return err;
+
+ /* supported rate */
+ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE,
+ cfg.rate, cfg.rate);
+ if (err < 0)
+ return err;
+
+ /* supported block size */
+ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
+ cfg.pkt_len, cfg.pkt_len);
+ if (err < 0)
+ return err;
+
+ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS,
+ 2, 200);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static int bluetooth_recvmsg_fd(struct bluetooth_data *data)
+{
+ char cmsg_b[CMSG_SPACE(sizeof(int))];
+ struct ipc_packet pkt;
+ int err, ret;
+ struct iovec iov = {
+ .iov_base = &pkt,
+ .iov_len = sizeof(pkt)
+ };
+ struct msghdr msgh = {
+ .msg_name = 0,
+ .msg_namelen = 0,
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = &cmsg_b,
+ .msg_controllen = CMSG_LEN(sizeof(int)),
+ .msg_flags = 0
+ };
+
+ ret = recvmsg(data->sock, &msgh, 0);
+
+ if (ret < 0) {
+ err = errno;
+ SNDERR("Unable to receive fd: %s (%d)", strerror(err), err);
+ return -err;
+ }
+
+ if (pkt.type == PKT_TYPE_CFG_RSP) {
+ struct cmsghdr *cmsg;
+ /* Receive auxiliary data in msgh */
+ for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msgh,cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET
+ && cmsg->cmsg_type == SCM_RIGHTS)
+ data->cfg.fd = (*(int *) CMSG_DATA(cmsg));
+ DBG("fd = %d", data->cfg.fd);
+ return 0;
+ }
+ }
+ else
+ SNDERR("Unexpected packet type received: type = %d", pkt.type);
+
+ return -EINVAL;
+}
+
+static int bluetooth_cfg(struct bluetooth_data *data)
+{
+ int ret, len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_cfg);
+ struct ipc_packet *pkt;
+
+ DBG("Sending PKT_TYPE_CFG_REQ...");
+
+ if ((pkt = malloc(len)) == 0)
+ return -ENOMEM;
+
+ memset(pkt, 0, len);
+ pkt->type = PKT_TYPE_CFG_REQ;
+ pkt->role = PKT_ROLE_NONE;
+ pkt->error = PKT_ERROR_NONE;
+
+ if ((ret = send(data->sock, pkt, len, 0)) < 0) {
+ ret = -errno;
+ goto done;
+ } else if (ret == 0) {
+ ret = -EIO;
+ goto done;
+ }
+
+ DBG("OK - %d bytes sent", ret);
+
+ DBG("Waiting for response...");
+
+ memset(pkt, 0, len);
+ if ((ret = recv(data->sock, pkt, len, 0)) < 0) {
+ ret = -errno;
+ goto done;
+ } else if (ret == 0) {
+ ret = -EIO;
+ goto done;
+ }
+
+ DBG("OK - %d bytes received", ret);
+
+ if (pkt->type != PKT_TYPE_CFG_RSP) {
+ SNDERR("Unexpected packet type received: type = %d",
+ pkt->type);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (pkt->error != PKT_ERROR_NONE) {
+ SNDERR("Error while configuring device: error = %d",
+ pkt->error);
+ ret = pkt->error;
+ goto done;
+ }
+
+ if (pkt->length != sizeof(struct ipc_data_cfg)) {
+ SNDERR("Error while configuring device: packet size doesn't "
+ "match");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ memcpy(&data->cfg, pkt->data, sizeof(struct ipc_data_cfg));
+
+ DBG("Device configuration:");
+
+ DBG("fd=%d, fd_opt=%u, channels=%u, pkt_len=%u, sample_size=%u,"
+ "rate=%u", data->cfg.fd, data->cfg.fd_opt,
+ data->cfg.channels, data->cfg.pkt_len,
+ data->cfg.sample_size, data->cfg.rate);
+
+ if (data->cfg.fd == -1) {
+ SNDERR("Error while configuring device: could not acquire "
+ "audio socket");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((ret = bluetooth_recvmsg_fd(data)) < 0)
+ goto done;
+
+ if ((data->buffer = malloc(data->cfg.pkt_len)) == 0)
+ return -ENOMEM;
+
+ /* It is possible there is some outstanding
+ data in the pipe - we have to empty it */
+ while(recv(data->cfg.fd, data->buffer, data->cfg.pkt_len,
+ MSG_DONTWAIT) > 0);
+
+ memset(data->buffer, 0, data->cfg.pkt_len);
+
+done:
+ free(pkt);
+ return ret;
+}
+
+static int bluetooth_init(struct bluetooth_data *data)
+{
+ int sk, err, id;
+ struct sockaddr_un addr = {
+ AF_UNIX, IPC_SOCKET_NAME
+ };
+
+ if (!data)
+ return -EINVAL;
+
+ memset(data, 0, sizeof(struct bluetooth_data));
+
+ data->sock = -1;
+
+ id = abs(getpid() * rand());
+
+ if ((sk = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
+ err = -errno;
+ SNDERR("Can't open socket");
+ return -errno;
+ }
+
+ DBG("Connecting to address: %s", addr.sun_path + 1);
+ if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ err = -errno;
+ SNDERR("Can't connect socket");
+ close(sk);
+ return err;
+ }
+
+ data->sock = sk;
+
+ if ((err = bluetooth_cfg(data)) < 0)
return err;
return 0;
@@ -154,86 +523,32 @@
SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)
{
- snd_config_iterator_t iter, next;
struct bluetooth_data *data;
- struct sockaddr_un addr;
- unsigned int id;
- int sk, err;
+ int err;
DBG("Bluetooth PCM plugin (%s)",
stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture");
- snd_config_for_each(iter, next, conf) {
- snd_config_t *n = snd_config_iterator_entry(iter);
- const char *id;
-
- if (snd_config_get_id(n, &id) < 0)
- continue;
-
- if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0)
- continue;
-
- if (strcmp(id, "bdaddr") == 0) {
- const char *str;
- if (snd_config_get_string(n, &str) < 0) {
- SNDERR("Invalid type for %s", id);
- return -EINVAL;
- }
- printf("bdaddr %s\n", str);
- continue;
- }
-
- SNDERR("Unknown field %s", id);
-
- return -EINVAL;
- }
-
- id = abs(getpid() * rand());
-
- sk = socket(PF_LOCAL, SOCK_DGRAM, 0);
- if (sk < 0) {
- SNDERR("Can't open socket");
- return -errno;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s/%d", SOCKET_NAME, id);
-
- if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- SNDERR("Can't bind socket");
- close(sk);
- return -errno;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- snprintf(addr.sun_path + 1, UNIX_PATH_MAX - 2, "%s", SOCKET_NAME);
-
- if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- SNDERR("Can't connect socket");
- close(sk);
- return -errno;
- }
-
- data = malloc(sizeof(*data));
+ data = malloc(sizeof(struct bluetooth_data));
+ memset(data, 0, sizeof(struct bluetooth_data));
if (!data) {
- close(sk);
- return -ENOMEM;
- }
-
- memset(data, 0, sizeof(*data));
-
- data->sock = sk;
+ err = -ENOMEM;
+ goto error;
+ }
+
+ err = bluetooth_init(data);
+ if (err < 0)
+ goto error;
data->io.version = SND_PCM_IOPLUG_VERSION;
- data->io.name = "Bluetooth Audio";
- data->io.mmap_rw = 0; /* No direct mmap communication */
+ data->io.name = "Bluetooth Audio Device";
+ data->io.mmap_rw = 0; /* No direct mmap communication */
data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ?
&bluetooth_playback_callback : &bluetooth_capture_callback;
- data->io.poll_fd = sk;
- data->io.poll_events = POLLIN;
+ data->io.poll_fd = data->cfg.fd;
+ data->io.poll_events = stream == SND_PCM_STREAM_PLAYBACK ?
+ POLLOUT : POLLIN;
data->io.private_data = data;
err = snd_pcm_ioplug_create(&data->io, name, stream, mode);
@@ -243,7 +558,7 @@
err = bluetooth_hw_constraint(&data->io);
if (err < 0) {
snd_pcm_ioplug_delete(&data->io);
- goto error;
+ goto error;
}
*pcmp = data->io.pcm;
@@ -251,9 +566,7 @@
return 0;
error:
- close(sk);
-
- free(data);
+ bluetooth_exit(data);
return err;
}
Added: bluez-utils/branches/upstream/current/audio/test-audio
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/test-audio?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/test-audio (added)
+++ bluez-utils/branches/upstream/current/audio/test-audio Wed Jul 4 13:37:57 2007
@@ -1,0 +1,19 @@
+#!/usr/bin/python
+
+import dbus
+
+bus = dbus.SystemBus()
+
+manager = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'),
+ 'org.bluez.Manager')
+
+conn = manager.ActivateService('audio')
+
+audio = dbus.Interface(bus.get_object(conn, '/org/bluez/audio'),
+ 'org.bluez.audio.Manager')
+
+try:
+ headset = dbus.Interface(bus.get_object(conn, audio.DefaultHeadset()),
+ 'org.bluez.audio.Headset')
+except:
+ pass
Propchange: bluez-utils/branches/upstream/current/audio/test-audio
------------------------------------------------------------------------------
svn:executable = *
Added: bluez-utils/branches/upstream/current/audio/unix.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/unix.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/unix.c (added)
+++ bluez-utils/branches/upstream/current/audio/unix.c Wed Jul 4 13:37:57 2007
@@ -1,0 +1,217 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <assert.h>
+
+#include <glib.h>
+
+#include "logging.h"
+#include "dbus.h"
+
+#include "manager.h"
+
+static int unix_sock = -1;
+
+/* Pass file descriptor through local domain sockets (AF_LOCAL, formerly AF_UNIX)
+and the sendmsg() system call with the cmsg_type field of a "struct cmsghdr" set
+to SCM_RIGHTS and the data being an integer value equal to the handle of the
+file descriptor to be passed.*/
+static int unix_sendmsg_fd(int sock, int fd, struct ipc_packet *pkt)
+{
+ char cmsg_b[CMSG_SPACE(sizeof(int))];
+ struct cmsghdr *cmsg;
+ struct iovec iov = {
+ .iov_base = pkt,
+ .iov_len = sizeof(struct ipc_packet)
+ };
+
+ struct msghdr msgh = {
+ .msg_name = 0,
+ .msg_namelen = 0,
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = &cmsg_b,
+ .msg_controllen = CMSG_LEN(sizeof(int)),
+ .msg_flags = 0
+ };
+
+ cmsg = CMSG_FIRSTHDR(&msgh);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+ /* Initialize the payload */
+ (*(int *) CMSG_DATA(cmsg)) = fd;
+
+ return sendmsg(sock, &msgh, MSG_NOSIGNAL);
+}
+
+static gboolean unix_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ struct device *device;
+ struct sockaddr_un addr;
+ socklen_t addrlen;
+ struct ipc_packet *pkt;
+ struct ipc_data_cfg *cfg;
+ int sk, clisk, len;
+
+ debug("chan %p cond %td data %p", chan, cond, data);
+
+ if (cond & G_IO_NVAL)
+ return FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ g_io_channel_close(chan);
+ return FALSE;
+ }
+
+ sk = g_io_channel_unix_get_fd(chan);
+
+ memset(&addr, 0, sizeof(addr));
+ addrlen = sizeof(addr);
+
+ clisk = accept(sk, (struct sockaddr *) &addr, &addrlen);
+ if (clisk < 0) {
+ error("accept: %s (%d)", strerror(errno), errno);
+ return TRUE;
+ }
+
+ len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_cfg);
+ pkt = g_malloc0(len);
+ len = recv(clisk, pkt, len, 0);
+
+ debug("path %s len %d", addr.sun_path + 1, len);
+
+ switch (pkt->type) {
+ case PKT_TYPE_CFG_REQ:
+ info("Package PKT_TYPE_CFG_REQ:%u", pkt->role);
+
+ cfg = (struct ipc_data_cfg *) pkt->data;
+
+ memset(cfg, 0, sizeof(struct ipc_data_cfg));
+ if ((device = manager_default_device())) {
+ if (device->headset)
+ headset_get_config(device, clisk, pkt);
+ }
+
+ if (cfg->fd != 0)
+ unix_send_cfg(clisk, pkt);
+ break;
+ case PKT_TYPE_STATUS_REQ:
+ info("Package PKT_TYPE_STATUS_REQ");
+ break;
+ case PKT_TYPE_CTL_REQ:
+ info("Package PKT_TYPE_CTL_REQ");
+ break;
+ }
+
+ return TRUE;
+}
+
+int unix_init(void)
+{
+ GIOChannel *io;
+ struct sockaddr_un addr = {
+ AF_UNIX, IPC_SOCKET_NAME
+ };
+
+ int sk, err;
+
+ sk = socket(PF_LOCAL, SOCK_STREAM, 0);
+ if (sk < 0) {
+ err = errno;
+ error("Can't create unix socket: %s (%d)", strerror(err), err);
+ return -err;
+ }
+
+ if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ error("Can't bind unix socket: %s (%d)", strerror(errno), errno);
+ close(sk);
+ return -1;
+ }
+
+ set_nonblocking(sk);
+
+ unix_sock = sk;
+
+ listen(sk, 1);
+
+ io = g_io_channel_unix_new(sk);
+
+ g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ unix_event, NULL);
+
+ g_io_channel_unref(io);
+
+ info("Unix socket created: %d", sk);
+
+ return 0;
+}
+
+void unix_exit(void)
+{
+ close(unix_sock);
+ unix_sock = -1;
+}
+
+int unix_send_cfg(int sock, struct ipc_packet *pkt)
+{
+ struct ipc_data_cfg *cfg = (struct ipc_data_cfg *) pkt->data;
+ int len;
+
+ info("fd=%d, fd_opt=%u, channels=%u, pkt_len=%u, sample_size=%u,"
+ "rate=%u", cfg->fd, cfg->fd_opt, cfg->channels,
+ cfg->pkt_len, cfg->sample_size, cfg->rate);
+
+ pkt->type = PKT_TYPE_CFG_RSP;
+ pkt->length = sizeof(struct ipc_data_cfg);
+ pkt->error = PKT_ERROR_NONE;
+
+ len = sizeof(struct ipc_packet) + sizeof(struct ipc_data_cfg);
+ len = send(sock, pkt, len, 0);
+ if (len < 0)
+ info("Error %s(%d)", strerror(errno), errno);
+
+ info("%d bytes sent", len);
+
+ if (cfg->fd != -1) {
+ len = unix_sendmsg_fd(sock, cfg->fd, pkt);
+ if (len < 0)
+ info("Error %s(%d)", strerror(errno), errno);
+ info("%d bytes sent", len);
+ }
+
+ g_free(pkt);
+ close(sock);
+ return 0;
+}
Added: bluez-utils/branches/upstream/current/audio/unix.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/audio/unix.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/audio/unix.h (added)
+++ bluez-utils/branches/upstream/current/audio/unix.h Wed Jul 4 13:37:57 2007
@@ -1,0 +1,29 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "ipc.h"
+
+int unix_init(void);
+
+void unix_exit(void);
+int unix_send_cfg(int sock, struct ipc_packet *pkt);
Modified: bluez-utils/branches/upstream/current/common/dbus-helper.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/dbus-helper.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/dbus-helper.c (original)
+++ bluez-utils/branches/upstream/current/common/dbus-helper.c Wed Jul 4 13:37:57 2007
@@ -285,7 +285,7 @@
static void update_parent_data(DBusConnection *conn, const char *child_path)
{
- struct generic_data *data;
+ struct generic_data *data = NULL;
char *parent_path, *slash;
parent_path = g_strdup(child_path);
@@ -350,10 +350,10 @@
const char *path,
void **data_p)
{
- struct generic_data *data;
+ struct generic_data *data = NULL;
if (!dbus_connection_get_object_path_data(connection, path,
- (void *) &data))
+ (void *) &data) || !data)
return FALSE;
*data_p = data->user_data;
@@ -367,11 +367,11 @@
DBusSignalVTable *signals,
DBusPropertyVTable *properties)
{
- struct generic_data *data;
+ struct generic_data *data = NULL;
struct interface_data *iface;
if (!dbus_connection_get_object_path_data(connection, path,
- (void *) &data))
+ (void *) &data) || !data)
return FALSE;
if (find_interface(data->interfaces, name))
@@ -395,11 +395,11 @@
dbus_bool_t dbus_connection_unregister_interface(DBusConnection *connection,
const char *path, const char *name)
{
- struct generic_data *data;
+ struct generic_data *data = NULL;
struct interface_data *iface;
if (!dbus_connection_get_object_path_data(connection, path,
- (void *) &data))
+ (void *) &data) || !data)
return FALSE;
iface = find_interface(data->interfaces, name);
@@ -431,6 +431,9 @@
switch (type) {
case DBUS_TYPE_STRING:
sig = DBUS_TYPE_STRING_AS_STRING;
+ break;
+ case DBUS_TYPE_INT16:
+ sig = DBUS_TYPE_INT16_AS_STRING;
break;
case DBUS_TYPE_UINT32:
sig = DBUS_TYPE_UINT32_AS_STRING;
@@ -459,15 +462,15 @@
int first,
va_list var_args)
{
- struct generic_data *data;
+ struct generic_data *data = NULL;
struct interface_data *iface;
- DBusMessageIter iter;
DBusSignalVTable *sig_data;
DBusMessage *signal;
- int type;
- const char *args = NULL;
-
- if (!dbus_connection_get_object_path_data(conn, path, (void *) &data)) {
+ dbus_bool_t ret;
+ const char *signature, *args = NULL;
+
+ if (!dbus_connection_get_object_path_data(conn, path,
+ (void *) &data) || !data) {
error("dbus_connection_emit_signal: path %s isn't registered",
path);
return FALSE;
@@ -499,33 +502,23 @@
return FALSE;
}
- dbus_message_iter_init_append(signal, &iter);
-
- for (type = first; type != DBUS_TYPE_INVALID;
- type = va_arg(var_args, int), args++) {
- void *value;
-
- if (type != *args) {
- error("%s.%s: expected arg type '%c' but got '%c'",
- interface, name, *args, type);
- dbus_message_unref(signal);
- return FALSE;
- }
-
- value = va_arg(var_args, void *);
-
- if (!dbus_message_iter_append_basic(&iter, type, value)) {
- error("%s.%s: appending argument of type '%c' failed",
- interface, name, type);
- dbus_message_unref(signal);
- return FALSE;
- }
- }
-
- dbus_connection_send(conn, signal, NULL);
+ ret = dbus_message_append_args_valist(signal, first, var_args);
+ if (!ret)
+ goto fail;
+
+ signature = dbus_message_get_signature(signal);
+ if (strcmp(args, signature) != 0) {
+ error("%s.%s: expected signature'%s' but got '%s'",
+ interface, name, args, signature);
+ ret = FALSE;
+ goto fail;
+ }
+
+ ret = dbus_connection_send(conn, signal, NULL);
+fail:
dbus_message_unref(signal);
- return TRUE;
+ return ret;
}
dbus_bool_t dbus_connection_emit_signal(DBusConnection *conn, const char *path,
Modified: bluez-utils/branches/upstream/current/common/dbus.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/dbus.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/dbus.c (original)
+++ bluez-utils/branches/upstream/current/common/dbus.c Wed Jul 4 13:37:57 2007
@@ -61,6 +61,12 @@
GIOChannel *io;
DBusConnection *conn;
};
+
+struct server_info {
+ guint watch_id;
+ GIOChannel *io;
+ DBusServer *server;
+};
#endif
struct disconnect_data {
@@ -74,25 +80,34 @@
};
struct name_data {
+ DBusConnection *connection;
char *name;
GSList *callbacks;
};
-static struct name_data *name_data_find(const char *name)
+static struct name_data *name_data_find(DBusConnection *connection,
+ const char *name)
{
GSList *current;
- for (current = name_listeners; current != NULL; current = current->next) {
+ for (current = name_listeners;
+ current != NULL; current = current->next) {
struct name_data *data = current->data;
- if (strcmp(name, data->name) == 0)
- return data;
+
+ if (name == NULL && data->name == NULL) {
+ if (connection == data->connection)
+ return data;
+ } else {
+ if (strcmp(name, data->name) == 0)
+ return data;
+ }
}
return NULL;
}
static struct name_callback *name_callback_find(GSList *callbacks,
- name_cb_t func, void *user_data)
+ name_cb_t func, void *user_data)
{
GSList *current;
@@ -105,19 +120,36 @@
return NULL;
}
-static void name_data_free(struct name_data *data)
+static void name_data_call_and_free(struct name_data *data)
{
GSList *l;
- for (l = data->callbacks; l != NULL; l = l->next)
- g_free(l->data);
+ for (l = data->callbacks; l != NULL; l = l->next) {
+ struct name_callback *cb = l->data;
+ if (cb->func)
+ cb->func(data->name, cb->user_data);
+ g_free(cb);
+ }
g_slist_free(data->callbacks);
g_free(data->name);
g_free(data);
}
-static int name_data_add(const char *name, name_cb_t func, void *user_data)
+static void name_data_free(struct name_data *data)
+{
+ GSList *l;
+
+ for (l = data->callbacks; l != NULL; l = l->next)
+ g_free(l->data);
+
+ g_slist_free(data->callbacks);
+ g_free(data->name);
+ g_free(data);
+}
+
+static int name_data_add(DBusConnection *connection,
+ const char *name, name_cb_t func, void *user_data)
{
int first = 1;
struct name_data *data = NULL;
@@ -128,7 +160,7 @@
cb->func = func;
cb->user_data = user_data;
- data = name_data_find(name);
+ data = name_data_find(connection, name);
if (data) {
first = 0;
goto done;
@@ -136,6 +168,7 @@
data = g_new0(struct name_data, 1);
+ data->connection = connection;
data->name = g_strdup(name);
name_listeners = g_slist_append(name_listeners, data);
@@ -145,12 +178,13 @@
return first;
}
-static void name_data_remove(const char *name, name_cb_t func, void *user_data)
+static void name_data_remove(DBusConnection *connection,
+ const char *name, name_cb_t func, void *user_data)
{
struct name_data *data;
struct name_callback *cb = NULL;
- data = name_data_find(name);
+ data = name_data_find(connection, name);
if (!data)
return;
@@ -190,7 +224,7 @@
if (*new != '\0')
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- data = name_data_find(name);
+ data = name_data_find(connection, name);
if (!data) {
error("Got NameOwnerChanged signal for %s which has no listeners", name);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -215,50 +249,51 @@
int first;
if (!name_listener_initialized) {
- if (!dbus_connection_add_filter(connection, name_exit_filter, NULL, NULL)) {
+ if (!dbus_connection_add_filter(connection,
+ name_exit_filter, NULL, NULL)) {
error("dbus_connection_add_filter() failed");
return -1;
}
name_listener_initialized = 1;
}
- first = name_data_add(name, func, user_data);
+ first = name_data_add(connection, name, func, user_data);
/* The filter is already added if this is not the first callback
* registration for the name */
if (!first)
return 0;
- debug("name_listener_add(%s)", name);
-
- snprintf(match_string, sizeof(match_string),
- "interface=%s,member=NameOwnerChanged,arg0=%s",
- DBUS_INTERFACE_DBUS, name);
-
- dbus_error_init(&err);
- dbus_bus_add_match(connection, match_string, &err);
-
- if (dbus_error_is_set(&err)) {
- error("Adding match rule \"%s\" failed: %s", match_string,
- err.message);
- dbus_error_free(&err);
- name_data_remove(name, func, user_data);
- return -1;
+ if (name) {
+ debug("name_listener_add(%s)", name);
+
+ snprintf(match_string, sizeof(match_string),
+ "interface=%s,member=NameOwnerChanged,arg0=%s",
+ DBUS_INTERFACE_DBUS, name);
+
+ dbus_error_init(&err);
+ dbus_bus_add_match(connection, match_string, &err);
+
+ if (dbus_error_is_set(&err)) {
+ error("Adding match rule \"%s\" failed: %s",
+ match_string, err.message);
+ dbus_error_free(&err);
+ name_data_remove(connection, name, func, user_data);
+ return -1;
+ }
}
return 0;
}
int name_listener_remove(DBusConnection *connection, const char *name,
- name_cb_t func, void *user_data)
+ name_cb_t func, void *user_data)
{
struct name_data *data;
struct name_callback *cb;
DBusError err;
char match_string[128];
- debug("name_listener_remove(%s)", name);
-
- data = name_data_find(name);
+ data = name_data_find(connection, name);
if (!data) {
error("remove_name_listener: no listener for %s", name);
return -1;
@@ -277,21 +312,43 @@
if (data->callbacks)
return 0;
- snprintf(match_string, sizeof(match_string),
- "interface=%s,member=NameOwnerChanged,arg0=%s",
- DBUS_INTERFACE_DBUS, name);
-
- dbus_error_init(&err);
- dbus_bus_remove_match(connection, match_string, &err);
-
- if (dbus_error_is_set(&err)) {
- error("Removing owner match rule for %s failed: %s",
+ if (name) {
+ debug("name_listener_remove(%s)", name);
+
+ snprintf(match_string, sizeof(match_string),
+ "interface=%s,member=NameOwnerChanged,arg0=%s",
+ DBUS_INTERFACE_DBUS, name);
+
+ dbus_error_init(&err);
+
+ dbus_bus_remove_match(connection, match_string, &err);
+
+ if (dbus_error_is_set(&err)) {
+ error("Removing owner match rule for %s failed: %s",
name, err.message);
- dbus_error_free(&err);
+ dbus_error_free(&err);
+ return -1;
+ }
+ }
+
+ name_data_remove(connection, name, func, user_data);
+
+ return 0;
+}
+
+int name_listener_indicate_disconnect(DBusConnection *connection)
+{
+ struct name_data *data;
+
+ data = name_data_find(connection, NULL);
+ if (!data) {
+ error("name_listener_indicate_disconnect: no listener found");
return -1;
}
- name_data_remove(name, func, user_data);
+ debug("name_listener_indicate_disconnect");
+
+ name_data_call_and_free(data);
return 0;
}
@@ -371,6 +428,75 @@
}
#ifndef HAVE_DBUS_GLIB
+static dbus_int32_t server_slot = -1;
+
+static gboolean server_func(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ DBusWatch *watch = data;
+ int flags = 0;
+
+ if (cond & G_IO_IN) flags |= DBUS_WATCH_READABLE;
+ if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE;
+ if (cond & G_IO_HUP) flags |= DBUS_WATCH_HANGUP;
+ if (cond & G_IO_ERR) flags |= DBUS_WATCH_ERROR;
+
+ dbus_watch_handle(watch, flags);
+
+ return TRUE;
+}
+
+static dbus_bool_t add_server(DBusWatch *watch, void *data)
+{
+ GIOCondition cond = G_IO_HUP | G_IO_ERR;
+ DBusServer *server = data;
+ struct server_info *info;
+ int fd, flags;
+
+ if (!dbus_watch_get_enabled(watch))
+ return TRUE;
+
+ info = g_new(struct server_info, 1);
+
+ fd = dbus_watch_get_fd(watch);
+ info->io = g_io_channel_unix_new(fd);
+ info->server = dbus_server_ref(server);
+
+ dbus_watch_set_data(watch, info, NULL);
+
+ flags = dbus_watch_get_flags(watch);
+
+ if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN;
+ if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT;
+
+ info->watch_id = g_io_add_watch(info->io, cond, server_func, watch);
+
+ return TRUE;
+}
+
+static void remove_server(DBusWatch *watch, void *data)
+{
+ struct server_info *info = dbus_watch_get_data(watch);
+
+ dbus_watch_set_data(watch, NULL, NULL);
+
+ if (info) {
+ g_source_remove(info->watch_id);
+ g_io_channel_unref(info->io);
+ dbus_server_unref(info->server);
+ g_free(info);
+ }
+}
+
+static void server_toggled(DBusWatch *watch, void *data)
+{
+ /* Because we just exit on OOM, enable/disable is
+ * no different from add/remove */
+ if (dbus_watch_get_enabled(watch))
+ add_server(watch, data);
+ else
+ remove_server(watch, data);
+}
+
static gboolean message_dispatch_cb(void *data)
{
DBusConnection *connection = data;
@@ -520,6 +646,45 @@
}
#endif
+void setup_dbus_server_with_main_loop(DBusServer *server)
+{
+#ifdef HAVE_DBUS_GLIB
+ debug("Using D-Bus GLib server setup");
+
+ dbus_server_setup_with_g_main(server, NULL);
+#else
+ dbus_server_allocate_data_slot(&server_slot);
+ if (server_slot < 0)
+ return;
+
+ dbus_server_set_data(server, server_slot, server, NULL);
+
+ dbus_server_set_watch_functions(server, add_server, remove_server,
+ server_toggled, server, NULL);
+
+ dbus_server_set_timeout_functions(server, add_timeout, remove_timeout,
+ timeout_toggled, server, NULL);
+#endif
+}
+
+void setup_dbus_with_main_loop(DBusConnection *conn)
+{
+#ifdef HAVE_DBUS_GLIB
+ debug("Using D-Bus GLib connection setup");
+
+ dbus_connection_setup_with_g_main(conn, NULL);
+#else
+ dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
+ watch_toggled, conn, NULL);
+
+ dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
+ timeout_toggled, conn, NULL);
+
+ dbus_connection_set_dispatch_status_function(conn, dispatch_status_cb,
+ conn, NULL);
+#endif
+}
+
DBusConnection *init_dbus(const char *name,
void (*disconnect_cb)(void *), void *user_data)
{
@@ -537,18 +702,7 @@
return NULL;
}
-#ifdef HAVE_DBUS_GLIB
- dbus_connection_setup_with_g_main(conn, NULL);
-#else
- dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
- watch_toggled, conn, NULL);
-
- dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout,
- timeout_toggled, conn, NULL);
-
- dbus_connection_set_dispatch_status_function(conn, dispatch_status_cb,
- conn, NULL);
-#endif
+ setup_dbus_with_main_loop(conn);
if (name) {
dbus_error_init(&err);
@@ -589,6 +743,28 @@
return conn;
}
+DBusConnection *init_dbus_direct(const char *address)
+{
+ DBusConnection *conn;
+ DBusError err;
+
+ dbus_error_init(&err);
+
+ conn = dbus_connection_open(address, &err);
+
+ if (dbus_error_is_set(&err)) {
+ error("Can't connect to message server: %s", err.message);
+ dbus_error_free(&err);
+ return NULL;
+ }
+
+ setup_dbus_with_main_loop(conn);
+
+ dbus_connection_set_exit_on_disconnect(conn, FALSE);
+
+ return conn;
+}
+
DBusConnection *dbus_bus_system_setup_with_main_loop(const char *name,
void (*disconnect_cb)(void *), void *user_data)
{
Modified: bluez-utils/branches/upstream/current/common/dbus.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/dbus.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/dbus.h (original)
+++ bluez-utils/branches/upstream/current/common/dbus.h Wed Jul 4 13:37:57 2007
@@ -26,8 +26,13 @@
#include <dbus/dbus.h>
+void setup_dbus_server_with_main_loop(DBusServer *server);
+void setup_dbus_with_main_loop(DBusConnection *conn);
+
DBusConnection *init_dbus(const char *name,
void (*disconnect_cb)(void *), void *user_data);
+
+DBusConnection *init_dbus_direct(const char *address);
DBusConnection *dbus_bus_system_setup_with_main_loop(const char *name,
void (*disconnect_cb)(void *), void *user_data);
@@ -41,6 +46,7 @@
name_cb_t func, void *user_data);
int name_listener_remove(DBusConnection *connection, const char *name,
name_cb_t func, void *user_data);
+int name_listener_indicate_disconnect(DBusConnection *connection);
dbus_bool_t dbus_bus_get_unix_process_id(DBusConnection *conn, const char *name,
unsigned long *pid);
Modified: bluez-utils/branches/upstream/current/common/ppoll.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/ppoll.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/ppoll.h (original)
+++ bluez-utils/branches/upstream/current/common/ppoll.h Wed Jul 4 13:37:57 2007
@@ -1,4 +1,10 @@
-static inline int ppoll(struct pollfd *fds, nfds_t nfds,
+#ifdef ppoll
+#undef ppoll
+#endif
+
+#define ppoll compat_ppoll
+
+static inline int compat_ppoll(struct pollfd *fds, nfds_t nfds,
const struct timespec *timeout, const sigset_t *sigmask)
{
return poll(fds, nfds, timeout ? timeout->tv_sec * 1000 : 500);
Modified: bluez-utils/branches/upstream/current/common/sdp-expat.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/sdp-expat.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/sdp-expat.c (original)
+++ bluez-utils/branches/upstream/current/common/sdp-expat.c Wed Jul 4 13:37:57 2007
@@ -116,7 +116,8 @@
}
}
- context->stack_head->data = sdp_xml_parse_datatype(el, context->stack_head);
+ context->stack_head->data = sdp_xml_parse_datatype(el,
+ context->stack_head, context->sdprec);
/* Could not parse an entry */
if (context->stack_head->data == NULL)
Modified: bluez-utils/branches/upstream/current/common/sdp-glib.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/sdp-glib.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/sdp-glib.c (original)
+++ bluez-utils/branches/upstream/current/common/sdp-glib.c Wed Jul 4 13:37:57 2007
@@ -115,8 +115,8 @@
}
}
- ctx_data->stack_head->data =
- sdp_xml_parse_datatype(element_name, ctx_data->stack_head);
+ ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name,
+ ctx_data->stack_head, ctx_data->record);
if (ctx_data->stack_head->data == NULL)
error("Can't parse element %s", element_name);
@@ -213,7 +213,7 @@
record = sdp_record_alloc();
if (!record) {
- sdp_record_free(record);
+ free(ctx_data);
return NULL;
}
Modified: bluez-utils/branches/upstream/current/common/sdp-xml.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/sdp-xml.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/sdp-xml.c (original)
+++ bluez-utils/branches/upstream/current/common/sdp-xml.c Wed Jul 4 13:37:57 2007
@@ -440,17 +440,20 @@
return sdp_data_alloc(SDP_UUID128, &val);
}
-sdp_data_t *sdp_xml_parse_uuid(const char *data)
-{
- int len;
+sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
+{
+ sdp_data_t *ret;
char *endptr;
uint32_t val;
uint16_t val2;
+ int len;
len = strlen(data);
- if (len == 36)
- return sdp_xml_parse_uuid128(data);
+ if (len == 36) {
+ ret = sdp_xml_parse_uuid128(data);
+ goto result;
+ }
val = strtoll(data, &endptr, 16);
@@ -458,15 +461,20 @@
if (*endptr != '\0')
return NULL;
- if (val > USHRT_MAX)
- return sdp_data_alloc(SDP_UUID32, &val);
+ if (val > USHRT_MAX) {
+ ret = sdp_data_alloc(SDP_UUID32, &val);
+ goto result;
+ }
val2 = val;
- return sdp_data_alloc(SDP_UUID16, &val2);
-
- /* Should never get here */
- return NULL;
+ ret = sdp_data_alloc(SDP_UUID16, &val2);
+
+result:
+ if (record && ret)
+ sdp_pattern_add_uuid(record, &ret->val.uuid);
+
+ return ret;
}
sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd)
@@ -482,14 +490,14 @@
if (!strcmp("true", data)) {
val = 1;
}
-
+
else if (!strcmp("false", data)) {
val = 0;
}
else {
return NULL;
}
-
+
ret = sdp_data_alloc(dtd, &val);
break;
}
@@ -497,35 +505,35 @@
case SDP_INT8:
{
int8_t val = strtoul(data, &endptr, 0);
-
- /* Failed to parse */
- if ((endptr != data) && (*endptr != '\0'))
- return NULL;
-
- ret = sdp_data_alloc(dtd, &val);
- break;
- }
-
- case SDP_UINT8:
- {
- uint8_t val = strtoul(data, &endptr, 0);
/* Failed to parse */
if ((endptr != data) && (*endptr != '\0'))
return NULL;
-
- ret = sdp_data_alloc(dtd, &val);
- break;
- }
-
- case SDP_INT16:
- {
- int16_t val = strtoul(data, &endptr, 0);
+
+ ret = sdp_data_alloc(dtd, &val);
+ break;
+ }
+
+ case SDP_UINT8:
+ {
+ uint8_t val = strtoul(data, &endptr, 0);
/* Failed to parse */
if ((endptr != data) && (*endptr != '\0'))
return NULL;
-
+
+ ret = sdp_data_alloc(dtd, &val);
+ break;
+ }
+
+ case SDP_INT16:
+ {
+ int16_t val = strtoul(data, &endptr, 0);
+
+ /* Failed to parse */
+ if ((endptr != data) && (*endptr != '\0'))
+ return NULL;
+
ret = sdp_data_alloc(dtd, &val);
break;
}
@@ -534,9 +542,9 @@
{
uint16_t val = strtoul(data, &endptr, 0);
- /* Failed to parse */
+ /* Failed to parse */
if ((endptr != data) && (*endptr != '\0'))
- return NULL;
+ return NULL;
ret = sdp_data_alloc(dtd, &val);
break;
@@ -546,10 +554,10 @@
{
int32_t val = strtoul(data, &endptr, 0);
- /* Failed to parse */
+ /* Failed to parse */
if ((endptr != data) && (*endptr != '\0'))
- return NULL;
-
+ return NULL;
+
ret = sdp_data_alloc(dtd, &val);
break;
}
@@ -558,9 +566,9 @@
{
uint32_t val = strtoul(data, &endptr, 0);
- /* Failed to parse */
+ /* Failed to parse */
if ((endptr != data) && (*endptr != '\0'))
- return NULL;
+ return NULL;
ret = sdp_data_alloc(dtd, &val);
break;
@@ -570,10 +578,10 @@
{
int64_t val = strtoull(data, &endptr, 0);
- /* Failed to parse */
+ /* Failed to parse */
if ((endptr != data) && (*endptr != '\0'))
- return NULL;
-
+ return NULL;
+
ret = sdp_data_alloc(dtd, &val);
break;
}
@@ -582,9 +590,9 @@
{
uint64_t val = strtoull(data, &endptr, 0);
- /* Failed to parse */
+ /* Failed to parse */
if ((endptr != data) && (*endptr != '\0'))
- return NULL;
+ return NULL;
ret = sdp_data_alloc(dtd, &val);
break;
@@ -615,22 +623,7 @@
return ret;
}
-static sdp_data_t *sdp_xml_parse_url_with_size(const char *data, uint8_t dtd)
-{
- return sdp_data_alloc(dtd, data);
-}
-
-sdp_data_t *sdp_xml_parse_url(const char *data)
-{
- uint8_t dtd = SDP_URL_STR8;
-
- if (strlen(data) > UCHAR_MAX)
- dtd = SDP_URL_STR16;
-
- return sdp_xml_parse_url_with_size(data, dtd);
-}
-
-static char *sdp_xml_parse_text_decode(const char *data, char encoding, uint32_t *length)
+static char *sdp_xml_parse_string_decode(const char *data, char encoding, uint32_t *length)
{
int len = strlen(data);
char *text;
@@ -664,23 +657,27 @@
return text;
}
-#if 0
-static sdp_data_t *sdp_xml_parse_text_with_size(const char *data, char encoding, uint8_t dtd)
-{
- char *text;
+sdp_data_t *sdp_xml_parse_url(const char *data)
+{
+ uint8_t dtd = SDP_URL_STR8;
+ char *url;
uint32_t length;
sdp_data_t *ret;
- text = sdp_xml_parse_text_decode(data, encoding, &length);
- ret = sdp_data_alloc_with_length(dtd, text, length);
-
- debug("Unit size %d length %d: -->%s<--\n", ret->unitSize, length, text);
-
- free(text);
+ url = sdp_xml_parse_string_decode(data,
+ SDP_XML_ENCODING_NORMAL, &length);
+
+ if (length > UCHAR_MAX)
+ dtd = SDP_URL_STR16;
+
+ ret = sdp_data_alloc_with_length(dtd, url, length);
+
+ debug("URL size %d length %d: -->%s<--", ret->unitSize, length, url);
+
+ free(url);
return ret;
}
-#endif
sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
{
@@ -689,14 +686,14 @@
uint32_t length;
sdp_data_t *ret;
- text = sdp_xml_parse_text_decode(data, encoding, &length);
+ text = sdp_xml_parse_string_decode(data, encoding, &length);
if (length > UCHAR_MAX)
dtd = SDP_TEXT_STR16;
ret = sdp_data_alloc_with_length(dtd, text, length);
- debug("Unit size %d length %d: -->%s<--\n", ret->unitSize, length, text);
+ debug("Text size %d length %d: -->%s<--", ret->unitSize, length, text);
free(text);
@@ -759,7 +756,8 @@
return elem;
}
-sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem)
+sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
+ sdp_record_t *record)
{
const char *data = elem->text;
@@ -786,7 +784,7 @@
else if (!strcmp(el, "int128"))
return sdp_xml_parse_int(data, SDP_INT128);
else if (!strcmp(el, "uuid"))
- return sdp_xml_parse_uuid(data);
+ return sdp_xml_parse_uuid(data, record);
else if (!strcmp(el, "url"))
return sdp_xml_parse_url(data);
else if (!strcmp(el, "text"))
Modified: bluez-utils/branches/upstream/current/common/sdp-xml.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/common/sdp-xml.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/common/sdp-xml.h (original)
+++ bluez-utils/branches/upstream/current/common/sdp-xml.h Wed Jul 4 13:37:57 2007
@@ -37,7 +37,7 @@
sdp_data_t *sdp_xml_parse_text(const char *data, char encoding);
sdp_data_t *sdp_xml_parse_url(const char *data);
sdp_data_t *sdp_xml_parse_int(const char *data, uint8_t dtd);
-sdp_data_t *sdp_xml_parse_uuid(const char *data);
+sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record);
struct sdp_xml_data {
char *text; /* Pointer to the current buffer */
@@ -53,7 +53,8 @@
void sdp_xml_data_free(struct sdp_xml_data *elem);
struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem);
-sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem);
+sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
+ sdp_record_t *record);
sdp_record_t *sdp_xml_parse_record(const char *data, int size);
Modified: bluez-utils/branches/upstream/current/configure
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/configure?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/configure (original)
+++ bluez-utils/branches/upstream/current/configure Wed Jul 4 13:37:57 2007
@@ -1906,7 +1906,7 @@
# Define the identity of the package.
PACKAGE=bluez-utils
- VERSION=3.10.1
+ VERSION=3.12
cat >>confdefs.h <<_ACEOF
Modified: bluez-utils/branches/upstream/current/configure.in
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/configure.in?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/configure.in (original)
+++ bluez-utils/branches/upstream/current/configure.in Wed Jul 4 13:37:57 2007
@@ -1,7 +1,7 @@
AC_PREREQ(2.50)
AC_INIT()
-AM_INIT_AUTOMAKE(bluez-utils, 3.10.1)
+AM_INIT_AUTOMAKE(bluez-utils, 3.12)
AM_CONFIG_HEADER(config.h)
AM_MAINTAINER_MODE
Modified: bluez-utils/branches/upstream/current/cups/Makefile.am
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/cups/Makefile.am?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/cups/Makefile.am (original)
+++ bluez-utils/branches/upstream/current/cups/Makefile.am Wed Jul 4 13:37:57 2007
@@ -3,13 +3,19 @@
cupsdir = $(libdir)/cups/backend
cups_PROGRAMS = bluetooth
-else
-noinst_PROGRAMS = bluetooth
+
+bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c
+
+bluetooth_LDADD = $(top_builddir)/common/libhelper.a \
+ @DBUS_LIBS@ @GLIB_LIBS@ @BLUEZ_LIBS@
+
+if EXPAT
+bluetooth_LDADD += -lexpat
+endif
endif
-bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c
-bluetooth_LDADD = @BLUEZ_LIBS@
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@
-AM_CFLAGS = @BLUEZ_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common
MAINTAINERCLEANFILES = Makefile.in
Modified: bluez-utils/branches/upstream/current/cups/Makefile.in
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/cups/Makefile.in?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/cups/Makefile.in (original)
+++ bluez-utils/branches/upstream/current/cups/Makefile.in Wed Jul 4 13:37:57 2007
@@ -37,7 +37,7 @@
build_triplet = @build@
host_triplet = @host@
@CUPS_TRUE at cups_PROGRAMS = bluetooth$(EXEEXT)
- at CUPS_FALSE@noinst_PROGRAMS = bluetooth$(EXEEXT)
+ at CUPS_TRUE@@EXPAT_TRUE at am__append_1 = -lexpat
subdir = cups
DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -50,11 +50,15 @@
CONFIG_CLEAN_FILES =
am__installdirs = "$(DESTDIR)$(cupsdir)"
cupsPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
-PROGRAMS = $(cups_PROGRAMS) $(noinst_PROGRAMS)
-am_bluetooth_OBJECTS = main.$(OBJEXT) sdp.$(OBJEXT) spp.$(OBJEXT) \
- hcrp.$(OBJEXT)
+PROGRAMS = $(cups_PROGRAMS)
+am__bluetooth_SOURCES_DIST = main.c sdp.c spp.c hcrp.c
+ at CUPS_TRUE@am_bluetooth_OBJECTS = main.$(OBJEXT) sdp.$(OBJEXT) \
+ at CUPS_TRUE@ spp.$(OBJEXT) hcrp.$(OBJEXT)
bluetooth_OBJECTS = $(am_bluetooth_OBJECTS)
-bluetooth_DEPENDENCIES =
+am__DEPENDENCIES_1 =
+ at CUPS_TRUE@bluetooth_DEPENDENCIES = \
+ at CUPS_TRUE@ $(top_builddir)/common/libhelper.a \
+ at CUPS_TRUE@ $(am__DEPENDENCIES_1)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@@ -67,7 +71,7 @@
LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(bluetooth_SOURCES)
-DIST_SOURCES = $(bluetooth_SOURCES)
+DIST_SOURCES = $(am__bluetooth_SOURCES_DIST)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -242,9 +246,12 @@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
@CUPS_TRUE at cupsdir = $(libdir)/cups/backend
-bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c
-bluetooth_LDADD = @BLUEZ_LIBS@
-AM_CFLAGS = @BLUEZ_CFLAGS@
+ at CUPS_TRUE@bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c
+ at CUPS_TRUE@bluetooth_LDADD = $(top_builddir)/common/libhelper.a \
+ at CUPS_TRUE@ @DBUS_LIBS@ @GLIB_LIBS@ @BLUEZ_LIBS@ \
+ at CUPS_TRUE@ $(am__append_1)
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@
+INCLUDES = -I$(top_srcdir)/common
MAINTAINERCLEANFILES = Makefile.in
all: all-am
@@ -303,13 +310,6 @@
clean-cupsPROGRAMS:
@list='$(cups_PROGRAMS)'; for p in $$list; do \
- f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
- echo " rm -f $$p $$f"; \
- rm -f $$p $$f ; \
- done
-
-clean-noinstPROGRAMS:
- @list='$(noinst_PROGRAMS)'; for p in $$list; do \
f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
echo " rm -f $$p $$f"; \
rm -f $$p $$f ; \
@@ -470,7 +470,7 @@
clean: clean-am
clean-am: clean-cupsPROGRAMS clean-generic clean-libtool \
- clean-noinstPROGRAMS mostlyclean-am
+ mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
@@ -519,17 +519,16 @@
uninstall-am: uninstall-cupsPROGRAMS uninstall-info-am
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-cupsPROGRAMS \
- clean-generic clean-libtool clean-noinstPROGRAMS ctags \
- distclean distclean-compile distclean-generic \
- distclean-libtool distclean-tags distdir dvi dvi-am html \
- html-am info info-am install install-am install-cupsPROGRAMS \
- install-data install-data-am install-exec install-exec-am \
- install-info install-info-am install-man install-strip \
- installcheck installcheck-am installdirs maintainer-clean \
- maintainer-clean-generic mostlyclean mostlyclean-compile \
- mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
- tags uninstall uninstall-am uninstall-cupsPROGRAMS \
- uninstall-info-am
+ clean-generic clean-libtool ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-cupsPROGRAMS install-data install-data-am install-exec \
+ install-exec-am install-info install-info-am install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-cupsPROGRAMS uninstall-info-am
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
Modified: bluez-utils/branches/upstream/current/cups/main.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/cups/main.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/cups/main.c (original)
+++ bluez-utils/branches/upstream/current/cups/main.c Wed Jul 4 13:37:57 2007
@@ -38,11 +38,507 @@
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
+#include <glib.h>
+
+#include "dbus.h"
+#include "sdp-xml.h"
+
extern int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel);
extern int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm);
extern int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies);
extern int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies);
+
+#define PRINTER_SERVICE_CLASS_NAME "printer"
+
+struct cups_device {
+ char *bdaddr;
+ char *name;
+ char *id;
+};
+
+static GSList *device_list = NULL;
+static GMainLoop *loop = NULL;
+static DBusConnection *conn = NULL;
+
+#define ATTRID_1284ID 0x0300
+
+static char *parse_xml_sdp(const char *xml)
+{
+ sdp_record_t *sdp_record;
+ sdp_list_t *l;
+ char *str = NULL;
+
+ sdp_record = sdp_xml_parse_record(xml, strlen(xml));
+ if (sdp_record == NULL)
+ return NULL;
+ for (l = sdp_record->attrlist; l != NULL; l = l->next) {
+ sdp_data_t *data;
+
+ data = (sdp_data_t *) l->data;
+ if (data->attrId != ATTRID_1284ID)
+ continue;
+ /* Ignore the length, it's null terminated */
+ str = g_strdup(data->val.str + 2);
+ break;
+ }
+ sdp_record_free(sdp_record);
+
+ return str;
+}
+
+static char *device_get_ieee1284_id(const char *adapter, const char *bdaddr)
+{
+ guint service_handle;
+ DBusMessage *message, *reply;
+ DBusMessageIter iter, reply_iter, iter_array;
+ const char *hcr_print = "00001126-0000-1000-8000-00805f9b34fb";
+ char *xml, *id;
+
+ /* Look for the service handle of the HCRP service */
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "GetRemoteServiceHandles");
+ dbus_message_iter_init_append(message, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &hcr_print);
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init(reply, &reply_iter);
+ if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
+ dbus_message_unref(reply);
+ return NULL;
+ }
+
+ /* Hopefully we only get one handle, or take a punt */
+ dbus_message_iter_recurse(&reply_iter, &iter_array);
+ while (dbus_message_iter_get_arg_type(&iter_array) == DBUS_TYPE_UINT32) {
+ dbus_message_iter_get_basic(&iter_array, &service_handle);
+ dbus_message_iter_next(&iter_array);
+ }
+
+ dbus_message_unref(reply);
+
+ /* Now get the XML for the HCRP service record */
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "GetRemoteServiceRecordAsXML");
+ dbus_message_iter_init_append(message, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &service_handle);
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init(reply, &reply_iter);
+ dbus_message_iter_get_basic(&reply_iter, &xml);
+
+ id = parse_xml_sdp(xml);
+
+ dbus_message_unref(reply);
+
+ return id;
+}
+
+static void add_device_to_list(const char *name, const char *bdaddr, const char *id)
+{
+ struct cups_device *device;
+ GSList *l;
+
+ /* Look for the device in the list */
+ for (l = device_list; l != NULL; l = l->next) {
+ device = (struct cups_device *) l->data;
+
+ if (strcmp(device->bdaddr, bdaddr) == 0) {
+ g_free(device->name);
+ device->name = g_strdup(name);
+ return;
+ }
+ }
+
+ /* Or add it to the list if it's not there */
+ device = g_new0(struct cups_device, 1);
+ device->bdaddr = g_strdup(bdaddr);
+ device->name = g_strdup(name);
+ device->id = g_strdup(id);
+
+ device_list = g_slist_prepend(device_list, device);
+}
+
+static char *escape_name(const char *str, char orig, char dest)
+{
+ char *ret, *s;
+
+ ret = g_strdup(str);
+ while ((s = strchr(ret, orig)) != NULL)
+ s[0] = dest;
+ return ret;
+}
+
+static void print_printer_details(const char *name, const char *bdaddr, const char *id)
+{
+ char *uri, *escaped;
+ guint len;
+
+ escaped = escape_name(name, '\"', '\'');
+ len = strlen("bluetooth://") + 12 + 1;
+ uri = g_malloc(len);
+ snprintf(uri, len, "bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c",
+ bdaddr[0], bdaddr[1],
+ bdaddr[3], bdaddr[4],
+ bdaddr[6], bdaddr[7],
+ bdaddr[9], bdaddr[10],
+ bdaddr[12], bdaddr[13],
+ bdaddr[15], bdaddr[16]);
+ printf("network %s \"Unknown\" \"%s (Bluetooth)\"", uri, escaped);
+ if (id != NULL)
+ printf(" \"%s\"\n", id);
+ else
+ printf ("\n");
+ g_free(escaped);
+ g_free(uri);
+}
+
+static gboolean device_is_printer(const char *adapter, const char *bdaddr)
+{
+ char *class;
+ DBusMessage *message, *reply;
+ DBusMessageIter iter, reply_iter;
+
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "GetRemoteMinorClass");
+ dbus_message_iter_init_append(message, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!reply)
+ return FALSE;
+
+ dbus_message_iter_init(reply, &reply_iter);
+ dbus_message_iter_get_basic(&reply_iter, &class);
+
+ if (class != NULL && strcmp(class, PRINTER_SERVICE_CLASS_NAME) == 0) {
+ dbus_message_unref(reply);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static char *device_get_name(const char *adapter, const char *bdaddr)
+{
+ DBusMessage *message, *reply;
+ DBusMessageIter iter, reply_iter;
+ char *name;
+
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "GetRemoteName");
+ dbus_message_iter_init_append(message, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, NULL);
+
+ dbus_message_unref(message);
+
+ if (!reply)
+ return NULL;
+
+ dbus_message_iter_init(reply, &reply_iter);
+ dbus_message_iter_get_basic(&reply_iter, &name);
+
+ name = g_strdup(name);
+ dbus_message_unref(reply);
+
+ return name;
+}
+
+static void remote_device_found(const char *adapter, const char *bdaddr, guint class, int rssi)
+{
+ uint8_t major_index = (class >> 8) & 0x1F;
+ uint8_t minor_index;
+ uint8_t shift_minor = 0;
+ gboolean found = FALSE;
+ char *name, *id;
+
+ /* Check if we have a printer
+ * From hcid/dbus-adapter.c minor_class_str() */
+ if (major_index != 6)
+ return;
+
+ minor_index = (class >> 4) & 0x0F;
+ while (shift_minor < 4) {
+ if (((minor_index >> shift_minor) & 0x01) == 0x01) {
+ if (shift_minor == 3) {
+ found = TRUE;
+ break;
+ }
+ }
+ shift_minor++;
+ }
+
+ if (!found)
+ return;
+
+ name = device_get_name(adapter, bdaddr);
+ id = device_get_ieee1284_id(adapter, bdaddr);
+ add_device_to_list(name, bdaddr, id);
+ g_free(name);
+ g_free(id);
+}
+
+static void remote_name_updated(const char *bdaddr, const char *name)
+{
+ add_device_to_list(name, bdaddr, NULL);
+}
+
+static void discovery_completed(void)
+{
+ GSList *l;
+
+ for (l = device_list; l != NULL; l = l->next) {
+ struct cups_device *device = (struct cups_device *) l->data;
+
+ if (device->name == NULL)
+ device->name = escape_name(device->bdaddr, ':', '-');
+ print_printer_details(device->name, device->bdaddr, device->id);
+ g_free(device->name);
+ g_free(device->bdaddr);
+ g_free(device->id);
+ g_free(device);
+ }
+
+ g_slist_free(device_list);
+ device_list = NULL;
+
+ g_main_loop_quit(loop);
+}
+
+static void remote_device_disappeared(const char *bdaddr)
+{
+ GSList *l;
+
+ for (l = device_list; l != NULL; l = l->next) {
+ struct cups_device *device = (struct cups_device *) l->data;
+
+ if (strcmp(device->bdaddr, bdaddr) == 0) {
+ g_free(device->name);
+ g_free(device->bdaddr);
+ g_free(device);
+ device_list = g_slist_delete_link(device_list, l);
+ return;
+ }
+ }
+}
+
+static gboolean list_known_printers(const char *adapter)
+{
+ DBusMessageIter reply_iter, iter_array;
+ DBusError error;
+ DBusMessage *message, *reply;
+
+ message = dbus_message_new_method_call ("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "ListRemoteDevices");
+ if (message == NULL)
+ return FALSE;
+
+ dbus_error_init(&error);
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, &error);
+
+ dbus_message_unref(message);
+
+ if (&error != NULL && dbus_error_is_set(&error))
+ return FALSE;
+
+ dbus_message_iter_init(reply, &reply_iter);
+ if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
+ dbus_message_unref(reply);
+ return FALSE;
+ }
+
+ dbus_message_iter_recurse(&reply_iter, &iter_array);
+ while (dbus_message_iter_get_arg_type(&iter_array) == DBUS_TYPE_STRING) {
+ char *bdaddr;
+
+ dbus_message_iter_get_basic(&iter_array, &bdaddr);
+ if (device_is_printer(adapter, bdaddr)) {
+ char *name, *id;
+ name = device_get_name(adapter, bdaddr);
+ id = device_get_ieee1284_id(adapter, bdaddr);
+ add_device_to_list(name, bdaddr, id);
+ g_free(name);
+ g_free(id);
+ }
+ dbus_message_iter_next(&iter_array);
+ }
+
+ dbus_message_unref(reply);
+
+ return FALSE;
+}
+
+static DBusHandlerResult filter_func(DBusConnection *connection, DBusMessage *message, void *user_data)
+{
+ const char *adapter;
+
+ if (dbus_message_is_signal(message, "org.bluez.Adapter",
+ "RemoteDeviceFound")) {
+ char *bdaddr;
+ guint class;
+ int rssi;
+
+ dbus_message_get_args(message, NULL,
+ DBUS_TYPE_STRING, &bdaddr,
+ DBUS_TYPE_UINT32, &class,
+ DBUS_TYPE_INT32, &rssi,
+ DBUS_TYPE_INVALID);
+ adapter = dbus_message_get_path(message);
+ remote_device_found(adapter, bdaddr, class, rssi);
+ } else if (dbus_message_is_signal(message, "org.bluez.Adapter",
+ "RemoteNameUpdated")) {
+ char *bdaddr, *name;
+
+ dbus_message_get_args(message, NULL,
+ DBUS_TYPE_STRING, &bdaddr,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID);
+ remote_name_updated(bdaddr, name);
+ } else if (dbus_message_is_signal(message, "org.bluez.Adapter",
+ "RemoteDeviceDisappeared")) {
+ char *bdaddr;
+
+ dbus_message_get_args(message, NULL,
+ DBUS_TYPE_STRING, &bdaddr,
+ DBUS_TYPE_INVALID);
+ remote_device_disappeared(bdaddr);
+ } else if (dbus_message_is_signal(message, "org.bluez.Adapter",
+ "DiscoveryCompleted")) {
+ discovery_completed();
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void list_printers(void)
+{
+ /* 1. Connect to the bus
+ * 2. Get the manager
+ * 3. Get the default adapter
+ * 4. Get a list of devices
+ * 5. Get the class of each device
+ * 6. Print the details from each printer device
+ */
+ DBusError error;
+ dbus_bool_t hcid_exists;
+ DBusMessage *reply, *message;
+ DBusMessageIter reply_iter;
+ char *adapter, *match;
+ guint len;
+
+ conn = init_dbus(NULL, NULL, NULL);
+ if (conn == NULL)
+ return;
+
+ dbus_error_init(&error);
+ hcid_exists = dbus_bus_name_has_owner(conn, "org.bluez", &error);
+ if (&error != NULL && dbus_error_is_set(&error))
+ return;
+
+ if (!hcid_exists)
+ return;
+
+ /* Get the default adapter */
+ message = dbus_message_new_method_call("org.bluez", "/org/bluez",
+ "org.bluez.Manager",
+ "DefaultAdapter");
+ if (message == NULL) {
+ dbus_connection_unref(conn);
+ return;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block(conn,
+ message, -1, &error);
+
+ dbus_message_unref(message);
+
+ if (&error != NULL && dbus_error_is_set(&error)) {
+ dbus_connection_unref(conn);
+ return;
+ }
+
+ dbus_message_iter_init(reply, &reply_iter);
+ if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_STRING) {
+ dbus_message_unref(reply);
+ dbus_connection_unref(conn);
+ return;
+ }
+
+ dbus_message_iter_get_basic(&reply_iter, &adapter);
+ adapter = g_strdup(adapter);
+ dbus_message_unref(reply);
+
+ if (!dbus_connection_add_filter(conn, filter_func, adapter, g_free)) {
+ g_free(adapter);
+ dbus_connection_unref(conn);
+ return;
+ }
+
+#define MATCH_FORMAT \
+ "type='signal'," \
+ "interface='org.bluez.Adapter'," \
+ "sender='org.bluez'," \
+ "path='%s'"
+
+ len = strlen(MATCH_FORMAT) - 2 + strlen(adapter) + 1;
+ match = g_malloc(len);
+ snprintf(match, len, "type='signal',"
+ "interface='org.bluez.Adapter',"
+ "sender='org.bluez',"
+ "path='%s'",
+ adapter);
+ dbus_bus_add_match(conn, match, &error);
+ g_free(match);
+
+ message = dbus_message_new_method_call("org.bluez", adapter,
+ "org.bluez.Adapter",
+ "DiscoverDevicesWithoutNameResolving");
+
+ if (!dbus_connection_send_with_reply(conn, message, NULL, -1)) {
+ dbus_message_unref(message);
+ dbus_connection_unref(conn);
+ g_free(adapter);
+ return;
+ }
+ dbus_message_unref(message);
+
+ /* Also add the the recent devices */
+ g_timeout_add(0, (GSourceFunc) list_known_printers, adapter);
+
+ loop = g_main_loop_new(NULL, TRUE);
+ g_main_loop_run(loop);
+
+ dbus_connection_unref(conn);
+}
/*
* Usage: printer-uri job-id user title copies options [file]
@@ -73,7 +569,7 @@
#endif /* HAVE_SIGSET */
if (argc == 1) {
- puts("network bluetooth \"Unknown\" \"Bluetooth printer\"");
+ list_printers();
return 0;
}
Modified: bluez-utils/branches/upstream/current/daemon/Makefile.am
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/daemon/Makefile.am?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/daemon/Makefile.am (original)
+++ bluez-utils/branches/upstream/current/daemon/Makefile.am Wed Jul 4 13:37:57 2007
@@ -50,6 +50,7 @@
INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/sdpd
-EXTRA_DIST = bluetooth.conf echo.service hal-namespace.txt
+EXTRA_DIST = bluetooth.conf echo.service \
+ test-manager test-database hal-namespace.txt
MAINTAINERCLEANFILES = Makefile.in
Modified: bluez-utils/branches/upstream/current/daemon/Makefile.in
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/daemon/Makefile.in?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/daemon/Makefile.in (original)
+++ bluez-utils/branches/upstream/current/daemon/Makefile.in Wed Jul 4 13:37:57 2007
@@ -294,7 +294,9 @@
auth_agent_LDADD = @DBUS_LIBS@
AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@
INCLUDES = -I$(top_srcdir)/common -I$(top_srcdir)/sdpd
-EXTRA_DIST = bluetooth.conf echo.service hal-namespace.txt
+EXTRA_DIST = bluetooth.conf echo.service \
+ test-manager test-database hal-namespace.txt
+
MAINTAINERCLEANFILES = Makefile.in
all: all-am
Modified: bluez-utils/branches/upstream/current/daemon/echo.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/daemon/echo.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/daemon/echo.c (original)
+++ bluez-utils/branches/upstream/current/daemon/echo.c Wed Jul 4 13:37:57 2007
@@ -49,7 +49,8 @@
char *address;
};
-static gboolean session_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+static gboolean session_event(GIOChannel *chan,
+ GIOCondition cond, gpointer data)
{
unsigned char buf[672];
gsize len, written;
@@ -75,7 +76,7 @@
info("Canceling authorization for %s", address);
msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
- "org.bluez.Database", "CancelAuthorizationRequest");
+ "org.bluez.Database", "CancelAuthorizationRequest");
if (!msg) {
error("Allocation of method message failed");
return;
@@ -104,8 +105,9 @@
dbus_error_free(&err);
} else {
info("Accepting incoming connection");
- g_io_add_watch(auth->io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- session_event, NULL);
+ g_io_add_watch(auth->io,
+ G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ session_event, NULL);
}
g_io_channel_unref(auth->io);
@@ -169,7 +171,8 @@
return 0;
}
-static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+static gboolean connect_event(GIOChannel *chan,
+ GIOCondition cond, gpointer data)
{
DBusConnection *conn = data;
GIOChannel *io;
@@ -236,6 +239,7 @@
static int setup_sdp(DBusConnection *conn, uint8_t channel)
{
DBusMessage *msg, *reply;
+ DBusError err;
sdp_record_t *record;
sdp_buf_t buf;
sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;
@@ -305,7 +309,9 @@
dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
&buf.data, buf.data_size, DBUS_TYPE_INVALID);
- reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, NULL);
+ dbus_error_init(&err);
+
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
dbus_message_unref(msg);
@@ -313,6 +319,8 @@
if (!reply) {
error("Registration of service record failed");
+ error("%s", err.message);
+ dbus_error_free(&err);
return -1;
}
@@ -326,6 +334,7 @@
static int register_standalone(DBusConnection *conn)
{
DBusMessage *msg, *reply;
+ DBusError err;
const char *ident = "echo", *name = "Echo service", *desc = "";
info("Registering service");
@@ -341,12 +350,16 @@
DBUS_TYPE_STRING, &name,
DBUS_TYPE_STRING, &desc, DBUS_TYPE_INVALID);
- reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, NULL);
+ dbus_error_init(&err);
+
+ reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
dbus_message_unref(msg);
if (!reply) {
error("Registration of service failed");
+ error("%s", err.message);
+ dbus_error_free(&err);
return -1;
}
@@ -364,15 +377,12 @@
g_main_loop_quit(main_loop);
}
-static void sig_hup(int sig)
-{
-}
-
int main(int argc, char *argv[])
{
- DBusConnection *system_bus;
- GIOChannel *server_io;
+ DBusConnection *conn;
+ GIOChannel *io;
struct sigaction sa;
+ char *addr;
start_logging("echo", "Bluetooth echo service ver %s", VERSION);
@@ -381,40 +391,52 @@
sa.sa_handler = sig_term;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
- sa.sa_handler = sig_hup;
- sigaction(SIGHUP, &sa, NULL);
sa.sa_handler = SIG_IGN;
sigaction(SIGCHLD, &sa, NULL);
sigaction(SIGPIPE, &sa, NULL);
+ enable_debug();
+
+ addr = getenv("BLUETOOTHD_ADDRESS");
+ if (!addr) {
+ error("No D-Bus server address available");
+ exit(1);
+ }
+
+ debug("Bluetooth daemon at %s", addr);
+
main_loop = g_main_loop_new(NULL, FALSE);
- system_bus = init_dbus(NULL, NULL, NULL);
- if (!system_bus) {
- error("Connection to system bus failed");
+ if (argc > 1 && !strcmp(argv[1], "-s"))
+ conn = init_dbus_direct(addr);
+ else
+ conn = init_dbus(NULL, NULL, NULL);
+
+ if (!conn) {
+ error("Connection to bus failed");
g_main_loop_unref(main_loop);
exit(1);
}
- server_io = setup_rfcomm(system_bus, 23);
- if (!server_io) {
+ io = setup_rfcomm(conn, 23);
+ if (!io) {
error("Creation of server channel failed");
- dbus_connection_unref(system_bus);
+ dbus_connection_unref(conn);
g_main_loop_unref(main_loop);
exit(1);
}
- setup_sdp(system_bus, 23);
+ setup_sdp(conn, 23);
if (argc > 1 && !strcmp(argv[1], "-s"))
- register_standalone(system_bus);
+ register_standalone(conn);
g_main_loop_run(main_loop);
- g_io_channel_unref(server_io);
-
- dbus_connection_unref(system_bus);
+ g_io_channel_unref(io);
+
+ dbus_connection_unref(conn);
g_main_loop_unref(main_loop);
Added: bluez-utils/branches/upstream/current/daemon/test-database
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/daemon/test-database?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/daemon/test-database (added)
+++ bluez-utils/branches/upstream/current/daemon/test-database Wed Jul 4 13:37:57 2007
@@ -1,0 +1,119 @@
+#!/usr/bin/python
+
+import time
+import dbus
+
+bus = dbus.SystemBus()
+
+xml = ' \
+<?xml version="1.0" encoding="UTF-8" ?> \
+<record> \
+ <attribute id="0x0001"> \
+ <sequence> \
+ <uuid value="0x1101"/> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id="0x0002"> \
+ <uint32 value="0"/> \
+ </attribute> \
+ \
+ <attribute id="0x0003"> \
+ <uuid value="00001101-0000-1000-8000-00805f9b34fb"/> \
+ </attribute> \
+ \
+ <attribute id="0x0004"> \
+ <sequence> \
+ <sequence> \
+ <uuid value="0x0100"/> \
+ </sequence> \
+ <sequence> \
+ <uuid value="0x0003"/> \
+ <uint8 value="23"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id="0x0005"> \
+ <sequence> \
+ <uuid value="0x1002"/> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id="0x0006"> \
+ <sequence> \
+ <uint16 value="0x656e"/> \
+ <uint16 value="0x006a"/> \
+ <uint16 value="0x0100"/> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id="0x0007"> \
+ <uint32 value="0"/> \
+ </attribute> \
+ \
+ <attribute id="0x0008"> \
+ <uint8 value="0xff"/> \
+ </attribute> \
+ \
+ <attribute id="0x0009"> \
+ <sequence> \
+ <sequence> \
+ <uuid value="0x1101"/> \
+ <uint16 value="0x0100"/> \
+ </sequence> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id="0x000a"> \
+ <url value="http://www.bluez.org/"/> \
+ </attribute> \
+ \
+ <attribute id="0x000b"> \
+ <url value="http://www.bluez.org/"/> \
+ </attribute> \
+ \
+ <attribute id="0x000c"> \
+ <url value="http://www.bluez.org/"/> \
+ </attribute> \
+ \
+ <attribute id="0x0100"> \
+ <text value="Serial Port"/> \
+ </attribute> \
+ \
+ <attribute id="0x0101"> \
+ <text value="Serial Port Service"/> \
+ </attribute> \
+ \
+ <attribute id="0x0102"> \
+ <text value="BlueZ"/> \
+ </attribute> \
+ \
+ <attribute id="0x0200"> \
+ <sequence> \
+ <uint16 value="0x0100"/> \
+ </sequence> \
+ </attribute> \
+ \
+ <attribute id="0x0201"> \
+ <uint32 value="0"/> \
+ </attribute> \
+</record> \
+'
+
+database = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'),
+ 'org.bluez.Database')
+
+handle = database.AddServiceRecordFromXML(xml)
+
+print "Service record with handle 0x%04x added" % (handle)
+
+print "Press CTRL-C to remove service record"
+
+try:
+ time.sleep(1000)
+ print "Terminating session"
+except:
+ pass
+
+database.RemoveServiceRecord(dbus.UInt32(handle))
Propchange: bluez-utils/branches/upstream/current/daemon/test-database
------------------------------------------------------------------------------
svn:executable = *
Added: bluez-utils/branches/upstream/current/daemon/test-manager
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/daemon/test-manager?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/daemon/test-manager (added)
+++ bluez-utils/branches/upstream/current/daemon/test-manager Wed Jul 4 13:37:57 2007
@@ -1,0 +1,27 @@
+#!/usr/bin/python
+
+import gobject
+
+import dbus
+import dbus.mainloop.glib
+
+def adapter_added(path):
+ print "Adapter with path %s added" % (path)
+
+def adapter_removed(path):
+ print "Adapter with path %s removed" % (path)
+
+if __name__ == "__main__":
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ manager = dbus.Interface(bus.get_object('org.bluez', '/org/bluez'),
+ 'org.bluez.Manager')
+
+ manager.connect_to_signal("AdapterAdded", adapter_added)
+
+ manager.connect_to_signal("AdapterRemoved", adapter_removed)
+
+ mainloop = gobject.MainLoop()
+ mainloop.run()
Propchange: bluez-utils/branches/upstream/current/daemon/test-manager
------------------------------------------------------------------------------
svn:executable = *
Modified: bluez-utils/branches/upstream/current/eglib/gmain.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/eglib/gmain.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/eglib/gmain.c (original)
+++ bluez-utils/branches/upstream/current/eglib/gmain.c Wed Jul 4 13:37:57 2007
@@ -1127,6 +1127,77 @@
}
}
+GSList *g_slist_nth(GSList *list, guint n)
+{
+ while (n-- > 0 && list)
+ list = list->next;
+
+ return list;
+}
+
+gpointer g_slist_nth_data(GSList *list, guint n)
+{
+ while (n-- > 0 && list)
+ list = list->next;
+
+ return list ? list->data : NULL;
+}
+
+gint g_slist_position(GSList *list, GSList *link)
+{
+ gint i;
+
+ for (i = 0; list; list = list->next, i++) {
+ if (list == link)
+ return i;
+ }
+
+ return -1;
+}
+
+GSList* g_slist_last(GSList *list)
+{
+ if (list)
+ while (list->next)
+ list = list->next;
+
+ return list;
+}
+
+static inline GSList* _g_slist_remove_link(GSList *list, GSList *link)
+{
+ GSList *tmp;
+ GSList *prev;
+
+ prev = NULL;
+ tmp = list;
+
+ while (tmp) {
+ if (tmp == link) {
+ if (prev)
+ prev->next = tmp->next;
+ if (list == tmp)
+ list = list->next;
+
+ tmp->next = NULL;
+ break;
+ }
+
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ return list;
+}
+
+GSList* g_slist_delete_link(GSList *list, GSList *link)
+{
+ list = _g_slist_remove_link(list, link);
+ g_free(link);
+
+ return list;
+}
+
/* Memory allocation functions */
gpointer g_malloc(gulong n_bytes)
Modified: bluez-utils/branches/upstream/current/eglib/gmain.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/eglib/gmain.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/eglib/gmain.h (original)
+++ bluez-utils/branches/upstream/current/eglib/gmain.h Wed Jul 4 13:37:57 2007
@@ -183,7 +183,7 @@
GSList *g_slist_find(GSList *list, gconstpointer data);
GSList *g_slist_find_custom(GSList *list, const void *data,
- GCompareFunc cmp_func);
+ GCompareFunc cmp_func);
GSList *g_slist_sort(GSList *list, GCompareFunc cmp_func);
@@ -191,6 +191,12 @@
void g_slist_foreach(GSList *list, GFunc func, void *user_data);
void g_slist_free(GSList *list);
+GSList *g_slist_delete_link(GSList *list, GSList *link);
+
+GSList *g_slist_nth(GSList *list, guint n);
+gpointer g_slist_nth_data(GSList *list, guint n);
+int g_slist_position(GSList *list, GSList *link);
+GSList* g_slist_last(GSList *list);
/* End GSList declarations */
Modified: bluez-utils/branches/upstream/current/hcid/Makefile.am
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/Makefile.am?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/Makefile.am (original)
+++ bluez-utils/branches/upstream/current/hcid/Makefile.am Wed Jul 4 13:37:57 2007
@@ -15,6 +15,7 @@
libhciserver_a_SOURCES = hcid.h security.c device.c \
storage.c parser.h parser.y lexer.l kword.c kword.h \
+ server.h server.c \
dbus-hci.h dbus-hci.c dbus-common.c dbus-common.h \
dbus-error.c dbus-error.h dbus-manager.c dbus-manager.h \
dbus-database.c dbus-database.h dbus-security.c dbus-security.h \
Modified: bluez-utils/branches/upstream/current/hcid/Makefile.in
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/Makefile.in?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/Makefile.in (original)
+++ bluez-utils/branches/upstream/current/hcid/Makefile.in Wed Jul 4 13:37:57 2007
@@ -57,11 +57,12 @@
libhciserver_a_LIBADD =
am_libhciserver_a_OBJECTS = security.$(OBJEXT) device.$(OBJEXT) \
storage.$(OBJEXT) parser.$(OBJEXT) lexer.$(OBJEXT) \
- kword.$(OBJEXT) dbus-hci.$(OBJEXT) dbus-common.$(OBJEXT) \
- dbus-error.$(OBJEXT) dbus-manager.$(OBJEXT) \
- dbus-database.$(OBJEXT) dbus-security.$(OBJEXT) \
- dbus-adapter.$(OBJEXT) dbus-device.$(OBJEXT) \
- dbus-service.$(OBJEXT) dbus-sdp.$(OBJEXT) dbus-test.$(OBJEXT)
+ kword.$(OBJEXT) server.$(OBJEXT) dbus-hci.$(OBJEXT) \
+ dbus-common.$(OBJEXT) dbus-error.$(OBJEXT) \
+ dbus-manager.$(OBJEXT) dbus-database.$(OBJEXT) \
+ dbus-security.$(OBJEXT) dbus-adapter.$(OBJEXT) \
+ dbus-device.$(OBJEXT) dbus-service.$(OBJEXT) \
+ dbus-sdp.$(OBJEXT) dbus-test.$(OBJEXT)
libhciserver_a_OBJECTS = $(am_libhciserver_a_OBJECTS)
am__installdirs = "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(man5dir)" \
"$(DESTDIR)$(man8dir)" "$(DESTDIR)$(confdir)" \
@@ -287,6 +288,7 @@
noinst_LIBRARIES = libhciserver.a
libhciserver_a_SOURCES = hcid.h security.c device.c \
storage.c parser.h parser.y lexer.l kword.c kword.h \
+ server.h server.c \
dbus-hci.h dbus-hci.c dbus-common.c dbus-common.h \
dbus-error.c dbus-error.h dbus-manager.c dbus-manager.h \
dbus-database.c dbus-database.h dbus-security.c dbus-security.h \
@@ -411,6 +413,7 @@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/main.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/parser.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/security.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/server.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/storage.Po at am__quote@
.c.o:
Modified: bluez-utils/branches/upstream/current/hcid/dbus-adapter.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-adapter.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-adapter.c (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-adapter.c Wed Jul 4 13:37:57 2007
@@ -228,27 +228,34 @@
return bonding;
}
-static const char *hcimode2str(uint8_t mode)
-{
- const char *scan_mode;
-
- switch (mode) {
- case SCAN_DISABLED:
- scan_mode = MODE_OFF;
- break;
- case SCAN_PAGE:
- scan_mode = MODE_CONNECTABLE;
- break;
- case (SCAN_PAGE | SCAN_INQUIRY):
- scan_mode = MODE_DISCOVERABLE;
- break;
- case SCAN_INQUIRY:
- /* inquiry scan mode is not handled, return unknown */
+const char *mode2str(uint8_t mode)
+{
+ switch(mode) {
+ case MODE_OFF:
+ return "off";
+ case MODE_CONNECTABLE:
+ return "connectable";
+ case MODE_DISCOVERABLE:
+ return "discoverable";
+ case MODE_LIMITED:
+ return "limited";
default:
- /* reserved */
- scan_mode = MODE_UNKNOWN;
- }
- return scan_mode;
+ return "unknown";
+ }
+}
+
+uint8_t str2mode(const char *mode)
+{
+ if (strcasecmp("off", mode) == 0)
+ return MODE_OFF;
+ else if (strcasecmp("connectable", mode) == 0)
+ return MODE_CONNECTABLE;
+ else if (strcasecmp("discoverable", mode) == 0)
+ return MODE_DISCOVERABLE;
+ else if (strcasecmp("limited", mode) == 0)
+ return MODE_LIMITED;
+ else
+ return MODE_UNKNOWN;
}
static DBusHandlerResult adapter_get_info(DBusConnection *conn,
@@ -301,8 +308,9 @@
dbus_message_iter_append_dict_entry(&dict, "company",
DBUS_TYPE_STRING, &property);
- property = hcimode2str(adapter->mode);
- dbus_message_iter_append_dict_entry(&dict, "mode",
+ property = mode2str(adapter->mode);
+
+ dbus_message_iter_append_dict_entry(&dict, "mode",
DBUS_TYPE_STRING, &property);
dbus_message_iter_append_dict_entry(&dict, "discoverable_timeout",
@@ -449,12 +457,40 @@
return send_message_and_unref(conn, reply);
}
+static DBusHandlerResult adapter_list_modes(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter;
+ DBusMessageIter array_iter;
+ const char *mode_ptr[] = { "off", "connectable", "discoverable", "limited" };
+ int i;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return error_invalid_arguments(conn, msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &array_iter);
+ for (i = 0; i < 4; i++)
+ dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING,
+ &mode_ptr[i]);
+
+ dbus_message_iter_close_container(&iter, &array_iter);
+
+ return send_message_and_unref(conn, reply);
+}
+
static DBusHandlerResult adapter_get_mode(DBusConnection *conn,
DBusMessage *msg, void *data)
{
const struct adapter *adapter = data;
DBusMessage *reply = NULL;
- const char *scan_mode;
+ const char *mode;
if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
return error_invalid_arguments(conn, msg);
@@ -463,8 +499,9 @@
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- scan_mode = hcimode2str(adapter->mode);
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &scan_mode,
+ mode = mode2str(adapter->mode);
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &mode,
DBUS_TYPE_INVALID);
return send_message_and_unref(conn, reply);
@@ -473,32 +510,38 @@
static DBusHandlerResult adapter_set_mode(DBusConnection *conn,
DBusMessage *msg, void *data)
{
- const struct adapter *adapter = data;
- DBusMessage *reply;
- const char* scan_mode;
- uint8_t hci_mode;
- const uint8_t current_mode = adapter->mode;
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ const char *mode;
+ uint8_t scan_enable;
+ uint8_t new_mode, current_scan = adapter->scan_enable;
bdaddr_t local;
- int dd;
+ gboolean limited;
+ int err, dd;
if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &scan_mode,
+ DBUS_TYPE_STRING, &mode,
DBUS_TYPE_INVALID))
return error_invalid_arguments(conn, msg);
- if (!scan_mode)
- return error_invalid_arguments(conn, msg);
-
- if (strcasecmp(MODE_OFF, scan_mode) == 0)
- hci_mode = SCAN_DISABLED;
- else if (strcasecmp(MODE_CONNECTABLE, scan_mode) == 0)
- hci_mode = SCAN_PAGE;
- else if (strcasecmp(MODE_DISCOVERABLE, scan_mode) == 0)
- hci_mode = (SCAN_PAGE | SCAN_INQUIRY);
- else
- return error_invalid_arguments(conn, msg);
-
- str2ba(adapter->address, &local);
+ if (!mode)
+ return error_invalid_arguments(conn, msg);
+
+ new_mode = str2mode(mode);
+ switch(new_mode) {
+ case MODE_OFF:
+ scan_enable = SCAN_DISABLED;
+ break;
+ case MODE_CONNECTABLE:
+ scan_enable = SCAN_PAGE;
+ break;
+ case MODE_DISCOVERABLE:
+ case MODE_LIMITED:
+ scan_enable = (SCAN_PAGE | SCAN_INQUIRY);
+ break;
+ default:
+ return error_invalid_arguments(conn, msg);
+ }
dd = hci_open_dev(adapter->dev_id);
if (dd < 0)
@@ -507,13 +550,13 @@
if (!adapter->up &&
(hcid.offmode == HCID_OFFMODE_NOSCAN ||
(hcid.offmode == HCID_OFFMODE_DEVDOWN &&
- hci_mode != SCAN_DISABLED))) {
+ scan_enable != SCAN_DISABLED))) {
/* Start HCI device */
if (ioctl(dd, HCIDEVUP, adapter->dev_id) == 0)
goto done; /* on success */
if (errno != EALREADY) {
- int err = errno;
+ err = errno;
error("Can't init device hci%d: %s (%d)\n",
adapter->dev_id, strerror(errno), errno);
@@ -522,7 +565,7 @@
}
}
- if (adapter->up && hci_mode == SCAN_DISABLED &&
+ if (adapter->up && scan_enable == SCAN_DISABLED &&
hcid.offmode == HCID_OFFMODE_DEVDOWN) {
if (ioctl(dd, HCIDEVDOWN, adapter->dev_id) < 0) {
hci_close_dev(dd);
@@ -532,22 +575,28 @@
goto done;
}
- /* Check if the new requested mode is different from the current */
- if (current_mode != hci_mode) {
+ limited = (new_mode == MODE_LIMITED ? TRUE : FALSE);
+ err = set_limited_discoverable(dd, adapter->class, limited);
+ if (err < 0) {
+ hci_close_dev(dd);
+ return error_failed(conn, msg, -err);
+ }
+
+ if (current_scan != scan_enable) {
struct hci_request rq;
uint8_t status = 0;
memset(&rq, 0, sizeof(rq));
rq.ogf = OGF_HOST_CTL;
rq.ocf = OCF_WRITE_SCAN_ENABLE;
- rq.cparam = &hci_mode;
- rq.clen = sizeof(hci_mode);
+ rq.cparam = &scan_enable;
+ rq.clen = sizeof(scan_enable);
rq.rparam = &status;
rq.rlen = sizeof(status);
rq.event = EVT_CMD_COMPLETE;
if (hci_send_req(dd, &rq, 1000) < 0) {
- int err = errno;
+ err = errno;
error("Sending write scan enable command failed: %s (%d)",
strerror(errno), errno);
hci_close_dev(dd);
@@ -560,16 +609,35 @@
hci_close_dev(dd);
return error_failed(conn, msg, bt_error(status));
}
- }
-
+ } else {
+ /* discoverable or limited */
+ if ((scan_enable & SCAN_INQUIRY) && (new_mode != adapter->mode)) {
+ dbus_connection_emit_signal(conn,
+ dbus_message_get_path(msg),
+ ADAPTER_INTERFACE,
+ "ModeChanged",
+ DBUS_TYPE_STRING, &mode,
+ DBUS_TYPE_INVALID);
+
+ if (adapter->timeout_id)
+ g_source_remove(adapter->timeout_id);
+
+ if (adapter->discov_timeout != 0)
+ adapter->timeout_id = g_timeout_add(adapter->discov_timeout * 1000,
+ discov_timeout_handler, adapter);
+ }
+ }
done:
- write_device_mode(&local, scan_mode);
+ str2ba(adapter->address, &local);
+ write_device_mode(&local, mode);
hci_close_dev(dd);
reply = dbus_message_new_method_return(msg);
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ adapter->mode = new_mode;
return send_message_and_unref(conn, reply);
}
@@ -620,7 +688,7 @@
adapter->timeout_id = 0;
}
- if ((timeout != 0) && (adapter->mode & SCAN_INQUIRY))
+ if ((timeout != 0) && (adapter->scan_enable & SCAN_INQUIRY))
adapter->timeout_id = g_timeout_add(timeout * 1000,
discov_timeout_handler,
adapter);
@@ -644,13 +712,13 @@
{
const struct adapter *adapter = data;
DBusMessage *reply;
- const uint8_t hci_mode = adapter->mode;
+ const uint8_t scan_enable = adapter->scan_enable;
dbus_bool_t connectable = FALSE;
if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
return error_invalid_arguments(conn, msg);
- if (hci_mode & SCAN_PAGE)
+ if (scan_enable & SCAN_PAGE)
connectable = TRUE;
reply = dbus_message_new_method_return(msg);
@@ -668,13 +736,13 @@
{
const struct adapter *adapter = data;
DBusMessage *reply;
- const uint8_t hci_mode = adapter->mode;
+ const uint8_t scan_enable = adapter->scan_enable;
dbus_bool_t discoverable = FALSE;
if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
return error_invalid_arguments(conn, msg);
- if (hci_mode & SCAN_INQUIRY)
+ if (scan_enable & SCAN_INQUIRY)
discoverable = TRUE;
reply = dbus_message_new_method_return(msg);
@@ -744,15 +812,14 @@
DBUS_TYPE_STRING_AS_STRING, &array_iter);
while (l) {
- char *peer_addr;
- bdaddr_t tmp;
+ char peer_addr[18];
+ const char *paddr = peer_addr;
struct active_conn_info *dev = l->data;
- baswap(&tmp, &dev->bdaddr); peer_addr = batostr(&tmp);
+ ba2str(&dev->bdaddr, peer_addr);
dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING,
- &peer_addr);
- bt_free(peer_addr);
+ &paddr);
l = l->next;
}
@@ -768,8 +835,6 @@
const struct adapter *adapter = data;
DBusMessage *reply;
const char *str_ptr = "computer";
- uint8_t cls[3];
- int dd;
if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
return error_invalid_arguments(conn, msg);
@@ -778,22 +843,8 @@
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- dd = hci_open_dev(adapter->dev_id);
- if (dd < 0)
- return error_no_such_adapter(conn, msg);
-
- if (hci_read_class_of_dev(dd, cls, 1000) < 0) {
- int err = errno;
- error("Can't read class of device on hci%d: %s(%d)",
- adapter->dev_id, strerror(errno), errno);
- hci_close_dev(dd);
- return error_failed(conn, msg, err);
- }
-
- hci_close_dev(dd);
-
/* FIXME: Currently, only computer major class is supported */
- if ((cls[1] & 0x1f) != 1)
+ if ((adapter->class[1] & 0x1f) != 1)
return error_unsupported_major_class(conn, msg);
dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr,
@@ -810,31 +861,13 @@
DBusMessageIter iter;
DBusMessageIter array_iter;
const char **minor_ptr;
- uint8_t cls[3];
uint8_t major_class;
- int dd, size, i;
-
- if (!adapter->up)
- return error_not_ready(conn, msg);
+ int size, i;
if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
return error_invalid_arguments(conn, msg);
- dd = hci_open_dev(adapter->dev_id);
- if (dd < 0)
- return error_no_such_adapter(conn, msg);
-
- if (hci_read_class_of_dev(dd, cls, 1000) < 0) {
- int err = errno;
- error("Can't read class of device on hci%d: %s(%d)",
- adapter->dev_id, strerror(errno), errno);
- hci_close_dev(dd);
- return error_failed(conn, msg, err);
- }
-
- hci_close_dev(dd);
-
- major_class = cls[1] & 0x1F;
+ major_class = adapter->class[1] & 0x1F;
switch (major_class) {
case 1: /* computer */
@@ -871,91 +904,63 @@
struct adapter *adapter = data;
DBusMessage *reply;
const char *str_ptr = "";
- uint8_t cls[3];
uint8_t minor_class;
- int dd;
+
+ if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ return error_invalid_arguments(conn, msg);
+
+ /* FIXME: Currently, only computer major class is supported */
+ if ((adapter->class[1] & 0x1f) != 1)
+ return error_unsupported_major_class(conn, msg);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ minor_class = adapter->class[0] >> 2;
+
+ /* Validate computer minor class */
+ if (minor_class > (sizeof(computer_minor_cls) / sizeof(*computer_minor_cls)))
+ goto failed;
+
+ str_ptr = computer_minor_cls[minor_class];
+
+failed:
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr,
+ DBUS_TYPE_INVALID);
+
+ return send_message_and_unref(conn, reply);
+}
+
+static DBusHandlerResult adapter_set_minor_class(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ DBusMessage *reply;
+ const char *minor;
+ uint32_t dev_class = 0xFFFFFFFF;
+ int i, dd;
if (!adapter->up)
return error_not_ready(conn, msg);
- if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &minor,
+ DBUS_TYPE_INVALID))
+ return error_invalid_arguments(conn, msg);
+
+ if (!minor)
return error_invalid_arguments(conn, msg);
dd = hci_open_dev(adapter->dev_id);
if (dd < 0)
return error_no_such_adapter(conn, msg);
- if (hci_read_class_of_dev(dd, cls, 1000) < 0) {
- int err = errno;
- error("Can't read class of device on hci%d: %s(%d)",
- adapter->dev_id, strerror(errno), errno);
+ /* Currently, only computer major class is supported */
+ if ((adapter->class[1] & 0x1f) != 1) {
hci_close_dev(dd);
- return error_failed(conn, msg, err);
- }
-
- hci_close_dev(dd);
-
- /* FIXME: Currently, only computer major class is supported */
- if ((cls[1] & 0x1f) != 1)
return error_unsupported_major_class(conn, msg);
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
-
- minor_class = cls[0] >> 2;
-
- /* Validate computer minor class */
- if (minor_class > (sizeof(computer_minor_cls) / sizeof(*computer_minor_cls)))
- goto failed;
-
- str_ptr = computer_minor_cls[minor_class];
-
-failed:
- dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_ptr,
- DBUS_TYPE_INVALID);
-
- return send_message_and_unref(conn, reply);
-}
-
-static DBusHandlerResult adapter_set_minor_class(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct adapter *adapter = data;
- DBusMessage *reply;
- bdaddr_t bdaddr;
- const char *minor;
- uint8_t cls[3];
- uint32_t dev_class = 0xFFFFFFFF;
- int i, dd;
-
- if (!adapter->up)
- return error_not_ready(conn, msg);
-
- if (!dbus_message_get_args(msg, NULL,
- DBUS_TYPE_STRING, &minor,
- DBUS_TYPE_INVALID))
- return error_invalid_arguments(conn, msg);
-
- if (!minor)
- return error_invalid_arguments(conn, msg);
-
- dd = hci_open_dev(adapter->dev_id);
- if (dd < 0)
- return error_no_such_adapter(conn, msg);
-
- if (hci_read_class_of_dev(dd, cls, 1000) < 0) {
- int err = errno;
- error("Can't read class of device on hci%d: %s(%d)",
- adapter->dev_id, strerror(errno), errno);
- hci_close_dev(dd);
- return error_failed(conn, msg, err);
- }
-
- /* Currently, only computer major class is supported */
- if ((cls[1] & 0x1f) != 1)
- return error_unsupported_major_class(conn, msg);
-
+ }
for (i = 0; i < sizeof(computer_minor_cls) / sizeof(*computer_minor_cls); i++)
if (!strcasecmp(minor, computer_minor_cls[i])) {
/* Remove the format type */
@@ -964,18 +969,13 @@
}
/* Check if it's a valid minor class */
- if (dev_class == 0xFFFFFFFF)
- return error_invalid_arguments(conn, msg);
-
- /* update the minor class before store */
- cls[0] = (dev_class & 0xff);
+ if (dev_class == 0xFFFFFFFF) {
+ hci_close_dev(dd);
+ return error_invalid_arguments(conn, msg);
+ }
/* set the service class and major class */
- dev_class |= (cls[2] << 16) | (cls[1] << 8);
-
- hci_devba(adapter->dev_id, &bdaddr);
-
- write_local_class(&bdaddr, cls);
+ dev_class |= (adapter->class[2] << 16) | (adapter->class[1] << 8);
if (hci_write_class_of_dev(dd, dev_class, 2000) < 0) {
int err = errno;
@@ -1006,8 +1006,7 @@
DBusMessageIter iter;
DBusMessageIter array_iter;
const char *str_ptr;
- uint8_t cls[3];
- int dd, i;
+ int i;
if (!adapter->up)
return error_not_ready(conn, msg);
@@ -1015,19 +1014,9 @@
if (!dbus_message_has_signature(msg, DBUS_TYPE_INVALID_AS_STRING))
return error_invalid_arguments(conn, msg);
- dd = hci_open_dev(adapter->dev_id);
- if (dd < 0)
- return error_no_such_adapter(conn, msg);
-
- if (hci_read_class_of_dev(dd, cls, 1000) < 0) {
- int err = errno;
- error("Can't read class of device on hci%d: %s(%d)",
- adapter->dev_id, strerror(errno), errno);
- hci_close_dev(dd);
- return error_failed(conn, msg, err);
- }
-
- reply = dbus_message_new_method_return(msg);
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
dbus_message_iter_init_append(reply, &iter);
@@ -1035,7 +1024,7 @@
DBUS_TYPE_STRING_AS_STRING, &array_iter);
for (i = 0; i < (sizeof(service_cls) / sizeof(*service_cls)); i++) {
- if (cls[2] & (1 << i)) {
+ if (adapter->class[2] & (1 << i)) {
str_ptr = service_cls[i];
dbus_message_iter_append_basic(&array_iter,
DBUS_TYPE_STRING, &str_ptr);
@@ -1043,8 +1032,6 @@
}
dbus_message_iter_close_container(&iter, &array_iter);
-
- hci_close_dev(dd);
return send_message_and_unref(conn, reply);
}
@@ -1276,6 +1263,13 @@
void *data)
{
return get_remote_svc_handles(conn, msg, data);
+}
+
+static DBusHandlerResult adapter_get_remote_svc_identifiers(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data)
+{
+ return get_remote_svc_identifiers(conn, msg, data);
}
static DBusHandlerResult adapter_finish_sdp_transact(DBusConnection *conn,
@@ -1978,7 +1972,7 @@
if (!l)
return error_not_connected(conn, msg);
- if(adapter->pending_dc)
+ if (adapter->pending_dc)
return error_disconnect_in_progress(conn, msg);
adapter->pending_dc = g_new0(struct pending_dc_info, 1);
@@ -1989,7 +1983,7 @@
dc_pending_timeout_handler,
adapter);
- if(!adapter->pending_dc->timeout_id) {
+ if (!adapter->pending_dc->timeout_id) {
g_free(adapter->pending_dc);
adapter->pending_dc = NULL;
return DBUS_HANDLER_RESULT_NEED_MEMORY;
@@ -3110,6 +3104,8 @@
"", "s" },
{ "GetCompany", adapter_get_company,
"", "s" },
+ { "ListAvailableModes", adapter_list_modes,
+ "", "as" },
{ "GetMode", adapter_get_mode,
"", "s" },
{ "SetMode", adapter_set_mode,
@@ -3140,7 +3136,7 @@
"", "s" },
{ "SetName", adapter_set_name,
"s", "" },
-
+
{ "GetRemoteInfo", adapter_get_remote_info,
"s", "{sv}" },
{ "GetRemoteServiceRecord", adapter_get_remote_svc,
@@ -3149,6 +3145,8 @@
"su", "s" },
{ "GetRemoteServiceHandles", adapter_get_remote_svc_handles,
"ss", "au" },
+ { "GetRemoteServiceIdentifiers", adapter_get_remote_svc_identifiers,
+ "s", "as" },
{ "FinishRemoteServiceTransaction", adapter_finish_sdp_transact,
"s", "" },
@@ -3255,8 +3253,11 @@
{ "RemoteDeviceConnected", "s" },
{ "RemoteDeviceDisconnectRequested", "s" },
{ "RemoteDeviceDisconnected", "s" },
+ { "RemoteIdentifiersUpdated", "sas" },
{ "BondingCreated", "s" },
{ "BondingRemoved", "s" },
+ { "TrustAdded", "s" },
+ { "TrustRemoved", "s" },
{ NULL, NULL }
};
@@ -3266,4 +3267,3 @@
adapter_methods,
adapter_signals, NULL);
}
-
Modified: bluez-utils/branches/upstream/current/hcid/dbus-adapter.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-adapter.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-adapter.h (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-adapter.h Wed Jul 4 13:37:57 2007
@@ -90,7 +90,9 @@
char address[18]; /* adapter Bluetooth Address */
guint timeout_id; /* discoverable timeout id */
uint32_t discov_timeout; /* discoverable time(msec) */
- uint8_t mode; /* scan mode */
+ uint8_t scan_enable; /* scan mode: SCAN_DISABLED, SCAN_PAGE, SCAN_INQUIRY */
+ uint8_t mode; /* off, connectable, discoverable, limited */
+ uint8_t class[3]; /* device class */
int discov_active; /* standard discovery active: includes name resolution step */
int pdiscov_active; /* periodic discovery active */
int pinq_idle; /* tracks the idle time for periodic inquiry */
@@ -116,6 +118,8 @@
const char *minor_class_str(uint32_t class);
+const char *mode2str(uint8_t mode);
+
GSList *service_classes_str(uint32_t class);
int pending_remote_name_cancel(struct adapter *adapter);
Modified: bluez-utils/branches/upstream/current/hcid/dbus-api.txt
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-api.txt?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-api.txt (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-api.txt Wed Jul 4 13:37:57 2007
@@ -354,11 +354,17 @@
Possible errors: org.bluez.Error.Failed
+ array{string} ListAvailableModes()
+
+ Returns a list of available modes the adapter can
+ be switched into.
+
string GetMode()
Returns the current mode of a adapter.
- Valid modes: "off", "connectable", "discoverable"
+ Valid modes: "off", "connectable", "discoverable",
+ "limited".
Possible errors: none
@@ -374,7 +380,7 @@
Returns the discoverable timeout in seconds. A value
of zero means that the timeout is disabled and it will
- stay in discoverable mode forever.
+ stay in discoverable/limited mode forever.
The default value for the discoverable timeout should
be 180 seconds (3 minutes).
@@ -385,10 +391,10 @@
Sets the discoverable timeout in seconds. A value of
zero disables the timeout and the adapter would be
- always discoverable.
+ always discoverable/limited.
Changing this value doesn't set the adapter into
- discoverable mode. The SetMode method must be used.
+ discoverable/limited mode. The SetMode method must be used.
Possible errors: org.bluez.Error.NotReady
org.bluez.Error.InvalidArguments
@@ -405,8 +411,8 @@
boolean IsDiscoverable()
- Returns true if the local adapter is discoverable and
- false if it is only connectable or switched off.
+ Returns true if the local adapter is discoverable/limited
+ and false if it is only connectable or switched off.
It is also possible to use GetMode to retrieve this
information.
@@ -434,9 +440,8 @@
For the other values, unsupported major class
error is returned.
- Possible errors: org.bluez.Error.NoSuchAdapter
+ Possible errors: org.bluez.Error.InvalidArguments
org.bluez.Error.UnsupportedMajorClass
- org.bluez.Error.Failed
array{string} ListAvailableMinorClasses()
@@ -448,9 +453,7 @@
If the major class is not "computer" an error should
be returned.
- Possible errors: org.bluez.Error.NotReady
- org.bluez.Error.NoSuchAdapter
- org.bluez.Error.Failed
+ Possible errors: org.bluez.Error.InvalidArguments
org.bluez.Error.UnsupportedMajorClass
string GetMinorClass()
@@ -466,10 +469,8 @@
The default value is "uncategorized".
- Possible errors: org.bluez.Error.NotReady
- org.bluez.Error.NoSuchAdapter
- org.bluez.Error.Failed
- org.bluez.Error.UnsupportedMajorClass
+ Possible errors:org.bluez.Error.InvalidArguments
+ org.bluez.Error.UnsupportedMajorClass
void SetMinorClass(string minor)
@@ -962,6 +963,15 @@
org.bluez.Error.InProgress
org.bluez.Error.Failed
+ array{string} GetRemoteServiceIdentifiers(string address)
+
+ This method will request the SDP database of a remote
+ device for all supported services. The identifiers are
+ returned in UUID 128 string format.
+
+ Possible errors: org.bluez.Error.InProgress
+ org.bluez.Error.Failed
+
void FinishRemoteServiceTransaction(string address)
This method will finish all SDP transaction for that
@@ -1054,6 +1064,13 @@
This signal will be send every time the service daemon
detect a new name for a remote device.
+
+ void RemoteIdentifiersUpdated(string address, array{string identifiers})
+
+ This signal is sent to indicate the provided services of a given
+ remote device. It will be sent after GetRemoteServiceIdentifiers
+ calls. This signal has at least one identifier and it does not
+ contain repeated entries.
void RemoteNameFailed(string address)
Modified: bluez-utils/branches/upstream/current/hcid/dbus-common.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-common.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-common.c (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-common.c Wed Jul 4 13:37:57 2007
@@ -207,45 +207,6 @@
return 0;
}
-
-int check_address(const char *addr)
-{
- char tmp[18];
- char *ptr = tmp;
-
- if (!addr)
- return -1;
-
- if (strlen(addr) != 17)
- return -1;
-
- memcpy(tmp, addr, 18);
-
- while (*ptr) {
-
- *ptr = toupper(*ptr);
- if (*ptr < '0'|| (*ptr > '9' && *ptr < 'A') || *ptr > 'F')
- return -1;
-
- ptr++;
- *ptr = toupper(*ptr);
- if (*ptr < '0'|| (*ptr > '9' && *ptr < 'A') || *ptr > 'F')
- return -1;
-
- ptr++;
- *ptr = toupper(*ptr);
- if (*ptr == 0)
- break;
-
- if (*ptr != ':')
- return -1;
-
- ptr++;
- }
-
- return 0;
-}
-
void hcid_dbus_set_experimental(void)
{
experimental = 1;
Modified: bluez-utils/branches/upstream/current/hcid/dbus-common.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-common.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-common.h (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-common.h Wed Jul 4 13:37:57 2007
@@ -49,7 +49,7 @@
int find_conn(int s, int dev_id, long arg);
-int check_address(const char *addr);
+#define check_address(address) bachk(address)
DBusHandlerResult handle_method_call(DBusConnection *conn, DBusMessage *msg, void *data);
Modified: bluez-utils/branches/upstream/current/hcid/dbus-database.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-database.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-database.c (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-database.c Wed Jul 4 13:37:57 2007
@@ -227,7 +227,6 @@
DBusMessage *msg, void *data)
{
struct record_data *user_record;
- DBusMessage *reply;
DBusMessageIter iter, array;
sdp_record_t *sdp_record;
dbus_uint32_t handle;
@@ -247,20 +246,14 @@
if (!user_record)
return error_not_available(conn, msg);
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
-
sdp_record = sdp_extract_pdu(bin_record, &scanned);
if (!sdp_record) {
error("Parsing of service record failed");
- dbus_message_unref(reply);
return error_invalid_arguments(conn, msg);
}
if (scanned != size) {
error("Size mismatch of service record");
- dbus_message_unref(reply);
sdp_record_free(sdp_record);
return error_invalid_arguments(conn, msg);
}
@@ -271,17 +264,25 @@
sdp_record->handle = handle;
err = add_record_to_server(sdp_record);
- } else
+ if (err < 0) {
+ sdp_record_free(sdp_record);
+ error("Failed to update the service record");
+ return error_failed(conn, msg, EIO);
+ }
+ } else {
+ sdp_data_t *d = sdp_data_alloc(SDP_UINT32, &handle);
+ sdp_attr_replace(sdp_record, SDP_ATTR_RECORD_HANDLE, d);
+
err = update_sdp_record(handle, sdp_record);
-
- if (err < 0) {
- error("Failed to update the service record");
- dbus_message_unref(reply);
sdp_record_free(sdp_record);
- return error_failed(conn, msg, EIO);
- }
-
- return send_message_and_unref(conn, reply);
+ if (err < 0) {
+ error("Failed to update the service record");
+ return error_failed(conn, msg, EIO);
+ }
+ }
+
+ return send_message_and_unref(conn,
+ dbus_message_new_method_return(msg));
}
static DBusHandlerResult remove_service_record(DBusConnection *conn,
@@ -336,7 +337,7 @@
sender = dbus_message_get_sender(msg);
- if (service_register(sender, ident, name, desc) < 0)
+ if (service_register(conn, sender, ident, name, desc) < 0)
return error_failed(conn, msg, EIO);
reply = dbus_message_new_method_return(msg);
@@ -366,7 +367,7 @@
if (!service->external || strcmp(sender, service->bus_name))
return error_not_authorized(conn, msg);
- if (service_unregister(service) < 0)
+ if (service_unregister(conn, service) < 0)
return error_failed(conn, msg, EIO);
reply = dbus_message_new_method_return(msg);
@@ -460,6 +461,27 @@
NULL, NULL);
}
+DBusHandlerResult database_message(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMethodVTable *current;
+
+ for (current = database_methods;
+ current->name && current->message_function; current++) {
+ if (!dbus_message_is_method_call(msg, DATABASE_INTERFACE,
+ current->name))
+ continue;
+
+ if (dbus_message_has_signature(msg, current->signature)) {
+ debug("%s: %s.%s()", dbus_message_get_path(msg),
+ DATABASE_INTERFACE, current->name);
+ return current->message_function(conn, msg, data);
+ }
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
void set_sdp_server_enable(void)
{
sdp_server_enable = 1;
Modified: bluez-utils/branches/upstream/current/hcid/dbus-database.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-database.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-database.h (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-database.h Wed Jul 4 13:37:57 2007
@@ -21,13 +21,11 @@
*
*/
-#ifndef __BLUEZ_DBUS_DATABASE_H
-#define __BLUEZ_DBUS_DATABASE_H
-
#define DATABASE_INTERFACE "org.bluez.Database"
dbus_bool_t database_init(DBusConnection *conn, const char *path);
+DBusHandlerResult database_message(DBusConnection *conn,
+ DBusMessage *msg, void *data);
+
void set_sdp_server_enable(void);
-
-#endif /* __BLUEZ_DBUS_DATABSE_H */
Modified: bluez-utils/branches/upstream/current/hcid/dbus-hci.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-hci.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-hci.c (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-hci.c Wed Jul 4 13:37:57 2007
@@ -262,24 +262,34 @@
return ret;
}
-static void adapter_mode_changed(struct adapter *adapter, const char *path, uint8_t mode)
-{
- const char *scan_mode;
-
- adapter->mode = mode;
-
- switch (mode) {
+static void adapter_mode_changed(struct adapter *adapter,
+ const char *path, uint8_t scan_enable)
+{
+ const char *mode;
+
+ adapter->scan_enable = scan_enable;
+
+ switch (scan_enable) {
case SCAN_DISABLED:
- scan_mode = MODE_OFF;
- break;
+ mode = "off";
+ adapter->mode = MODE_OFF;
+ break;
case SCAN_PAGE:
- scan_mode = MODE_CONNECTABLE;
+ mode = "connectable";
+ adapter->mode = MODE_CONNECTABLE;
break;
case (SCAN_PAGE | SCAN_INQUIRY):
- scan_mode = MODE_DISCOVERABLE;
+
if (adapter->discov_timeout != 0)
adapter->timeout_id = g_timeout_add(adapter->discov_timeout * 1000,
discov_timeout_handler, adapter);
+
+ if (adapter->mode == MODE_LIMITED) {
+ mode = "limited";
+ } else {
+ adapter->mode = MODE_DISCOVERABLE;
+ mode = "discoverable";
+ }
break;
case SCAN_INQUIRY:
/* Address the scenario where another app changed the scan mode */
@@ -294,7 +304,7 @@
dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE,
"ModeChanged",
- DBUS_TYPE_STRING, &scan_mode,
+ DBUS_TYPE_STRING, &mode,
DBUS_TYPE_INVALID);
}
@@ -428,7 +438,7 @@
dc_pending_timeout_cleanup(adapter);
}
- g_free (adapter);
+ g_free(adapter);
unreg:
if (!dbus_connection_destroy_object_path(connection, path)) {
@@ -542,7 +552,7 @@
struct adapter* adapter;
struct hci_conn_list_req *cl = NULL;
struct hci_conn_info *ci;
- uint8_t mode;
+ const char *mode;
int i, err, dd = -1, ret = -1;
snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -570,14 +580,13 @@
adapter->discov_timeout = get_discoverable_timeout(id);
adapter->discov_type = DISCOVER_TYPE_NONE;
- mode = get_startup_mode(id);
-
dd = hci_open_dev(id);
if (dd < 0)
goto failed;
- hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE, 1, &mode);
-
+ adapter->scan_enable = get_startup_scan(id);
+ hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
+ 1, &adapter->scan_enable);
/*
* Get the adapter Bluetooth address
*/
@@ -586,7 +595,13 @@
if (err < 0)
goto failed;
- adapter_mode_changed(adapter, path, mode);
+ err = get_device_class(adapter->dev_id, adapter->class);
+ if (err < 0)
+ goto failed;
+
+ adapter->mode = get_startup_mode(id);
+ if (adapter->mode == MODE_LIMITED)
+ set_limited_discoverable(dd, adapter->class, TRUE);
/*
* retrieve the active connections: address the scenario where
@@ -608,6 +623,12 @@
ret = 0;
+ mode = mode2str(adapter->mode);
+ dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE,
+ "ModeChanged",
+ DBUS_TYPE_STRING, &mode,
+ DBUS_TYPE_INVALID);
+
failed:
if (ret == 0 && get_default_adapter() < 0)
set_default_adapter(id);
@@ -637,7 +658,7 @@
{
char path[MAX_PATH_LENGTH];
struct adapter *adapter;
- const char *scan_mode = MODE_OFF;
+ const char *mode = "off";
snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -701,11 +722,12 @@
}
send_adapter_signal(connection, adapter->dev_id, "ModeChanged",
- DBUS_TYPE_STRING, &scan_mode,
+ DBUS_TYPE_STRING, &mode,
DBUS_TYPE_INVALID);
adapter->up = 0;
- adapter->mode = SCAN_DISABLED;
+ adapter->scan_enable = SCAN_DISABLED;
+ adapter->mode = MODE_OFF;
adapter->discov_active = 0;
adapter->pdiscov_active = 0;
adapter->pinq_idle = 0;
@@ -794,19 +816,18 @@
uint8_t status)
{
struct adapter *adapter;
- char *local_addr, *peer_addr;
+ char path[MAX_PATH_LENGTH], local_addr[18], peer_addr[18];
+ const char *paddr = peer_addr;
GSList *l;
- bdaddr_t tmp;
- char path[MAX_PATH_LENGTH];
int id;
- baswap(&tmp, local); local_addr = batostr(&tmp);
- baswap(&tmp, peer); peer_addr = batostr(&tmp);
+ ba2str(local, local_addr);
+ ba2str(peer, peer_addr);
id = hci_devid(local_addr);
if (id < 0) {
error("No matching device id for %s", local_addr);
- goto failed;
+ return;
}
snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -815,7 +836,7 @@
if (!dbus_connection_get_object_user_data(connection, path,
(void *) &adapter)) {
error("Getting %s path data failed!", path);
- goto failed;
+ return;
}
if (status)
@@ -831,14 +852,14 @@
if (!status)
send_adapter_signal(connection, adapter->dev_id,
"BondingCreated",
- DBUS_TYPE_STRING, &peer_addr,
+ DBUS_TYPE_STRING, &paddr,
DBUS_TYPE_INVALID);
}
release_passkey_agents(adapter, peer);
if (!adapter->bonding || bacmp(&adapter->bonding->bdaddr, peer))
- goto failed; /* skip: no bonding req pending */
+ return; /* skip: no bonding req pending */
if (adapter->bonding->cancel) {
/* reply authentication canceled */
@@ -860,26 +881,20 @@
g_io_channel_close(adapter->bonding->io);
bonding_request_free(adapter->bonding);
adapter->bonding = NULL;
-
-failed:
- bt_free(local_addr);
- bt_free(peer_addr);
}
void hcid_dbus_inquiry_start(bdaddr_t *local)
{
struct adapter *adapter;
- char path[MAX_PATH_LENGTH];
- char *local_addr;
- bdaddr_t tmp;
+ char path[MAX_PATH_LENGTH], local_addr[18];
int id;
- baswap(&tmp, local); local_addr = batostr(&tmp);
+ ba2str(local, local_addr);
id = hci_devid(local_addr);
if (id < 0) {
error("No matching device id for %s", local_addr);
- goto failed;
+ return;
}
snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -901,9 +916,6 @@
send_adapter_signal(connection, adapter->dev_id, "DiscoveryStarted",
DBUS_TYPE_INVALID);
-
-failed:
- bt_free(local_addr);
}
int found_device_req_name(struct adapter *adapter)
@@ -943,10 +955,9 @@
/* send at least one request or return failed if the list is empty */
do {
- const char *signal = NULL;
struct remote_dev_info *dev = l->data;
- char *peer_addr;
- bdaddr_t tmp;
+ char peer_addr[18];
+ const char *signal = NULL, *paddr = peer_addr;
/* flag to indicate the current remote name requested */
dev->name_status = NAME_REQUESTED;
@@ -956,7 +967,7 @@
bacpy(&cp.bdaddr, &dev->bdaddr);
cp.pscan_rep_mode = 0x02;
- baswap(&tmp, &dev->bdaddr); peer_addr = batostr(&tmp);
+ ba2str(&dev->bdaddr, peer_addr);
if (hci_send_req(dd, &rq, 500) < 0) {
error("Unable to send the HCI remote name request: %s (%d)",
@@ -979,10 +990,8 @@
if (signal)
send_adapter_signal(connection, adapter->dev_id, signal,
- DBUS_TYPE_STRING, &peer_addr,
+ DBUS_TYPE_STRING, &paddr,
DBUS_TYPE_INVALID);
-
- free(peer_addr);
if (req_sent)
break;
@@ -1024,18 +1033,16 @@
{
struct adapter *adapter;
GSList *l;
- char path[MAX_PATH_LENGTH];
- char *local_addr;
+ char path[MAX_PATH_LENGTH], local_addr[18];
struct remote_dev_info *dev;
bdaddr_t tmp;
int id;
- baswap(&tmp, local); local_addr = batostr(&tmp);
+ ba2str(local, local_addr);
id = hci_devid(local_addr);
if (id < 0) {
error("No matching device id for %s", local_addr);
- bt_free(local_addr);
return;
}
@@ -1124,28 +1131,23 @@
done:
/* Proceed with any queued up audits */
process_audits_list(path);
-
- bt_free(local_addr);
}
void hcid_dbus_periodic_inquiry_start(bdaddr_t *local, uint8_t status)
{
struct adapter *adapter;
- char path[MAX_PATH_LENGTH];
- char *local_addr;
- bdaddr_t tmp;
+ char path[MAX_PATH_LENGTH], local_addr[18];
int id;
/* Don't send the signal if the cmd failed */
if (status)
return;
- baswap(&tmp, local); local_addr = batostr(&tmp);
-
+ ba2str(local, local_addr);
id = hci_devid(local_addr);
if (id < 0) {
error("No matching device id for %s", local_addr);
- goto failed;
+ return;
}
snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1162,29 +1164,24 @@
dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE,
"PeriodicDiscoveryStarted",
DBUS_TYPE_INVALID);
-
-failed:
- bt_free(local_addr);
}
void hcid_dbus_periodic_inquiry_exit(bdaddr_t *local, uint8_t status)
{
struct adapter *adapter;
- char path[MAX_PATH_LENGTH];
- char *local_addr;
- bdaddr_t tmp;
+ char path[MAX_PATH_LENGTH], local_addr[18];
int id;
/* Don't send the signal if the cmd failed */
if (status)
return;
- baswap(&tmp, local); local_addr = batostr(&tmp);
+ ba2str(local, local_addr);
id = hci_devid(local_addr);
if (id < 0) {
error("No matching device id for %s", local_addr);
- goto done;
+ return;
}
snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1192,7 +1189,7 @@
if (!dbus_connection_get_object_user_data(connection, path,
(void *) &adapter)) {
error("Getting %s path data failed!", path);
- goto done;
+ return;
}
/* reset the discover type to be able to handle D-Bus and non D-Bus
@@ -1232,8 +1229,6 @@
dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE,
"PeriodicDiscoveryStopped",
DBUS_TYPE_INVALID);
-done:
- bt_free(local_addr);
}
static char *extract_eir_name(uint8_t *data, uint8_t *type)
@@ -1258,25 +1253,24 @@
void hcid_dbus_inquiry_result(bdaddr_t *local, bdaddr_t *peer, uint32_t class,
int8_t rssi, uint8_t *data)
{
- char filename[PATH_MAX + 1];
- char path[MAX_PATH_LENGTH];
+ char filename[PATH_MAX + 1], path[MAX_PATH_LENGTH];
struct adapter *adapter;
GSList *l;
+ char local_addr[18], peer_addr[18], *name, *tmp_name;
+ const char *paddr = peer_addr;
struct remote_dev_info match;
- char *local_addr, *peer_addr, *name, *tmp_name;
dbus_int16_t tmp_rssi = rssi;
- bdaddr_t tmp;
uint8_t name_type = 0x00;
name_status_t name_status;
int id;
- baswap(&tmp, local); local_addr = batostr(&tmp);
- baswap(&tmp, peer); peer_addr = batostr(&tmp);
+ ba2str(local, local_addr);
+ ba2str(peer, peer_addr);
id = hci_devid(local_addr);
if (id < 0) {
error("No matching device id for %s", local_addr);
- goto done;
+ return;
}
snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1284,7 +1278,7 @@
if (!dbus_connection_get_object_user_data(connection, path,
(void *) &adapter)) {
error("Getting %s path data failed!", path);
- goto done;
+ return;
}
write_remote_class(local, peer, class);
@@ -1314,7 +1308,7 @@
/* send the device found signal */
dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE,
"RemoteDeviceFound",
- DBUS_TYPE_STRING, &peer_addr,
+ DBUS_TYPE_STRING, &paddr,
DBUS_TYPE_UINT32, &class,
DBUS_TYPE_INT16, &tmp_rssi,
DBUS_TYPE_INVALID);
@@ -1326,7 +1320,7 @@
l = g_slist_find_custom(adapter->found_devices, &match,
(GCompareFunc) found_device_cmp);
if (l)
- goto done;
+ return;
/* the inquiry result can be triggered by NON D-Bus client */
if (adapter->discov_type & RESOLVE_NAME)
@@ -1359,7 +1353,7 @@
dbus_connection_emit_signal(connection, path,
ADAPTER_INTERFACE,
"RemoteNameUpdated",
- DBUS_TYPE_STRING, &peer_addr,
+ DBUS_TYPE_STRING, &paddr,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID);
g_free(name);
@@ -1370,16 +1364,12 @@
/* add in the list to track name sent/pending */
found_device_add(&adapter->found_devices, peer, rssi, name_status);
-
-done:
- bt_free(local_addr);
- bt_free(peer_addr);
}
void hcid_dbus_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class)
{
- char *local_addr, *peer_addr;
- bdaddr_t tmp;
+ char local_addr[18], peer_addr[18];
+ const char *paddr = peer_addr;
uint32_t old_class = 0;
int id;
@@ -1388,40 +1378,36 @@
if (old_class == class)
return;
- baswap(&tmp, local); local_addr = batostr(&tmp);
- baswap(&tmp, peer); peer_addr = batostr(&tmp);
+ ba2str(local, local_addr);
+ ba2str(peer, peer_addr);
id = hci_devid(local_addr);
if (id < 0) {
error("No matching device id for %s", local_addr);
- goto failed;
+ return;
}
send_adapter_signal(connection, id, "RemoteClassUpdated",
- DBUS_TYPE_STRING, &peer_addr,
+ DBUS_TYPE_STRING, &paddr,
DBUS_TYPE_UINT32, &class,
DBUS_TYPE_INVALID);
-failed:
- bt_free(local_addr);
- bt_free(peer_addr);
}
void hcid_dbus_remote_name(bdaddr_t *local, bdaddr_t *peer, uint8_t status,
char *name)
{
struct adapter *adapter;
- char path[MAX_PATH_LENGTH];
- char *local_addr, *peer_addr;
- bdaddr_t tmp;
+ char path[MAX_PATH_LENGTH], local_addr[18], peer_addr[18];
+ const char *paddr = peer_addr;
int id;
- baswap(&tmp, local); local_addr = batostr(&tmp);
- baswap(&tmp, peer); peer_addr = batostr(&tmp);
+ ba2str(local, local_addr);
+ ba2str(peer, peer_addr);
id = hci_devid(local_addr);
if (id < 0) {
error("No matching device id for %s", local_addr);
- goto done;
+ return;
}
snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1429,20 +1415,20 @@
if (!dbus_connection_get_object_user_data(connection, path,
(void *) &adapter)) {
error("Getting %s path data failed!", path);
- goto done;
+ return;
}
if (status)
dbus_connection_emit_signal(connection, path,
ADAPTER_INTERFACE,
"RemoteNameFailed",
- DBUS_TYPE_STRING, &peer_addr,
+ DBUS_TYPE_STRING, &paddr,
DBUS_TYPE_INVALID);
else
dbus_connection_emit_signal(connection, path,
ADAPTER_INTERFACE,
"RemoteNameUpdated",
- DBUS_TYPE_STRING, &peer_addr,
+ DBUS_TYPE_STRING, &paddr,
DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID);
@@ -1451,7 +1437,7 @@
/* check if there is more devices to request names */
if (!found_device_req_name(adapter))
- goto done; /* skip if a new request has been sent */
+ return; /* skip if a new request has been sent */
/* free discovered devices list */
g_slist_foreach(adapter->found_devices, (GFunc) g_free, NULL);
@@ -1489,28 +1475,23 @@
DBUS_TYPE_INVALID);
adapter->discov_active = 0;
}
-
-done:
- bt_free(local_addr);
- bt_free(peer_addr);
}
void hcid_dbus_conn_complete(bdaddr_t *local, uint8_t status, uint16_t handle,
bdaddr_t *peer)
{
- char path[MAX_PATH_LENGTH];
+ char path[MAX_PATH_LENGTH], local_addr[18], peer_addr[18];
+ const char *paddr = peer_addr;
struct adapter *adapter;
- char *local_addr, *peer_addr;
- bdaddr_t tmp;
int id;
- baswap(&tmp, local); local_addr = batostr(&tmp);
- baswap(&tmp, peer); peer_addr = batostr(&tmp);
+ ba2str(local, local_addr);
+ ba2str(peer, peer_addr);
id = hci_devid(local_addr);
if (id < 0) {
error("No matching device id for %s", local_addr);
- goto done;
+ return;
}
snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1518,7 +1499,7 @@
if (!dbus_connection_get_object_user_data(connection, path,
(void *) &adapter)) {
error("Getting %s path data failed!", path);
- goto done;
+ return;
}
if (status) {
@@ -1542,28 +1523,23 @@
dbus_connection_emit_signal(connection, path,
ADAPTER_INTERFACE,
"RemoteDeviceConnected",
- DBUS_TYPE_STRING, &peer_addr,
+ DBUS_TYPE_STRING, &paddr,
DBUS_TYPE_INVALID);
/* add in the active connetions list */
active_conn_append(&adapter->active_conn, peer, handle);
}
-
-done:
- bt_free(local_addr);
- bt_free(peer_addr);
}
void hcid_dbus_disconn_complete(bdaddr_t *local, uint8_t status,
uint16_t handle, uint8_t reason)
{
DBusMessage *reply;
- char path[MAX_PATH_LENGTH];
+ char path[MAX_PATH_LENGTH], local_addr[18], peer_addr[18];
+ const char *paddr = peer_addr;
struct adapter *adapter;
struct active_conn_info *dev;
GSList *l;
- char *local_addr, *peer_addr = NULL;
- bdaddr_t tmp;
int id;
if (status) {
@@ -1571,12 +1547,12 @@
return;
}
- baswap(&tmp, local); local_addr = batostr(&tmp);
+ ba2str(local, local_addr);
id = hci_devid(local_addr);
if (id < 0) {
error("No matching device id for %s", local_addr);
- goto failed;
+ return;
}
snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1584,18 +1560,18 @@
if (!dbus_connection_get_object_user_data(connection, path,
(void *) &adapter)) {
error("Getting %s path data failed!", path);
- goto failed;
+ return;
}
l = g_slist_find_custom(adapter->active_conn, &handle,
active_conn_find_by_handle);
if (!l)
- goto failed;
+ return;
dev = l->data;
- baswap(&tmp, &dev->bdaddr); peer_addr = batostr(&tmp);
+ ba2str(&dev->bdaddr, peer_addr);
/* clean pending HCI cmds */
hci_req_queue_remove(adapter->dev_id, &dev->bdaddr);
@@ -1650,17 +1626,51 @@
/* Send the remote device disconnected signal */
dbus_connection_emit_signal(connection, path, ADAPTER_INTERFACE,
"RemoteDeviceDisconnected",
- DBUS_TYPE_STRING, &peer_addr,
+ DBUS_TYPE_STRING, &paddr,
DBUS_TYPE_INVALID);
adapter->active_conn = g_slist_remove(adapter->active_conn, dev);
g_free(dev);
-failed:
- if (peer_addr)
- free(peer_addr);
-
- free(local_addr);
+}
+
+int set_limited_discoverable(int dd, const uint8_t *cls, gboolean limited)
+{
+ uint32_t dev_class;
+ int err;
+ int num = (limited ? 2 : 1);
+ uint8_t lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
+ /*
+ * 1: giac
+ * 2: giac + liac
+ */
+ if (hci_write_current_iac_lap(dd, num, lap, 1000) < 0) {
+ err = errno;
+ error("Can't write current IAC LAP: %s(%d)",
+ strerror(err), err);
+ return -err;
+ }
+
+ if (limited) {
+ if (cls[1] & 0x20)
+ return 0; /* Already limited */
+
+ dev_class = (cls[2] << 16) | ((cls[1] | 0x20) << 8) | cls[0];
+ } else {
+ if (!(cls[1] & 0x20))
+ return 0; /* Already clear */
+
+ dev_class = (cls[2] << 16) | ((cls[1] & 0xdf) << 8) | cls[0];
+ }
+
+ if (hci_write_class_of_dev(dd, dev_class, 1000) < 0) {
+ err = errno;
+ error("Can't write class of device: %s(%d)",
+ strerror(err), err);
+ return -err;
+ }
+
+ return 0;
}
gboolean discov_timeout_handler(void *data)
@@ -1668,11 +1678,11 @@
struct adapter *adapter = data;
struct hci_request rq;
int dd;
- uint8_t hci_mode = adapter->mode;
+ uint8_t scan_enable = adapter->scan_enable;
uint8_t status = 0;
gboolean retval = TRUE;
- hci_mode &= ~SCAN_INQUIRY;
+ scan_enable &= ~SCAN_INQUIRY;
dd = hci_open_dev(adapter->dev_id);
if (dd < 0) {
@@ -1683,8 +1693,8 @@
memset(&rq, 0, sizeof(rq));
rq.ogf = OGF_HOST_CTL;
rq.ocf = OCF_WRITE_SCAN_ENABLE;
- rq.cparam = &hci_mode;
- rq.clen = sizeof(hci_mode);
+ rq.cparam = &scan_enable;
+ rq.clen = sizeof(scan_enable);
rq.rparam = &status;
rq.rlen = sizeof(status);
rq.event = EVT_CMD_COMPLETE;
@@ -1698,6 +1708,8 @@
error("Setting scan enable failed with status 0x%02x", status);
goto failed;
}
+
+ set_limited_discoverable(dd, adapter->class, FALSE);
adapter->timeout_id = 0;
retval = FALSE;
@@ -1716,21 +1728,18 @@
*****************************************************************/
void hcid_dbus_setname_complete(bdaddr_t *local)
{
- char *local_addr;
- bdaddr_t tmp;
- int id;
- int dd = -1;
+ int id, dd = -1;
read_local_name_rp rp;
struct hci_request rq;
const char *pname = (char *) rp.name;
- char name[249];
-
- baswap(&tmp, local); local_addr = batostr(&tmp);
+ char local_addr[18], name[249];
+
+ ba2str(local, local_addr);
id = hci_devid(local_addr);
if (id < 0) {
error("No matching device id for %s", local_addr);
- goto failed;
+ return;
}
dd = hci_open_dev(id);
@@ -1756,6 +1765,7 @@
rp.status);
rp.name[0] = '\0';
}
+ hci_close_dev(dd);
}
strncpy(name, pname, sizeof(name) - 1);
@@ -1764,30 +1774,21 @@
send_adapter_signal(connection, id, "NameChanged",
DBUS_TYPE_STRING, &pname, DBUS_TYPE_INVALID);
-
-failed:
- if (dd >= 0)
- hci_close_dev(dd);
-
- bt_free(local_addr);
}
void hcid_dbus_setscan_enable_complete(bdaddr_t *local)
{
struct adapter *adapter;
- char *local_addr;
- char path[MAX_PATH_LENGTH];
- bdaddr_t tmp;
+ char path[MAX_PATH_LENGTH], local_addr[18];
read_scan_enable_rp rp;
struct hci_request rq;
- int id;
- int dd = -1;
-
- baswap(&tmp, local); local_addr = batostr(&tmp);
+ int id, dd = -1;
+
+ ba2str(local, local_addr);
id = hci_devid(local_addr);
if (id < 0) {
error("No matching device id for %s", local_addr);
- goto failed;
+ return;
}
snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1795,7 +1796,7 @@
dd = hci_open_dev(id);
if (dd < 0) {
error("HCI device open failed: hci%d", id);
- goto failed;
+ return;
}
memset(&rq, 0, sizeof(rq));
@@ -1828,14 +1829,53 @@
adapter->timeout_id = 0;
}
- if (adapter->mode != rp.enable)
+ if (adapter->scan_enable != rp.enable)
adapter_mode_changed(adapter, path, rp.enable);
failed:
if (dd >= 0)
hci_close_dev(dd);
-
- bt_free(local_addr);
+}
+
+void hcid_dbus_write_class_complete(bdaddr_t *local)
+{
+ struct adapter *adapter;
+ char path[MAX_PATH_LENGTH], local_addr[18];
+ int id, dd = -1;
+ uint8_t cls[3];
+
+ ba2str(local, local_addr);
+ id = hci_devid(local_addr);
+ if (id < 0) {
+ error("No matching device id for %s", local_addr);
+ return;
+ }
+
+ snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
+ if (!dbus_connection_get_object_user_data(connection, path,
+ (void *) &adapter)) {
+ error("Getting %s path data failed!", path);
+ return;
+ }
+
+ dd = hci_open_dev(id);
+ if (dd < 0) {
+ error("HCI device open failed: hci%d", id);
+ goto failed;
+ }
+
+ if (hci_read_class_of_dev(dd, cls, 1000) < 0) {
+ error("Can't read class of device on hci%d: %s(%d)",
+ id, strerror(errno), errno);
+ goto failed;
+ }
+
+ write_local_class(local, cls);
+ memcpy(adapter->class, cls, 3);
+
+failed:
+ if (dd >= 0)
+ hci_close_dev(dd);
}
void hcid_dbus_pin_code_reply(bdaddr_t *local, void *ptr)
@@ -1847,18 +1887,16 @@
} __attribute__ ((packed)) ret_pin_code_req_reply;
struct adapter *adapter;
- char *local_addr;
ret_pin_code_req_reply *ret = ptr + EVT_CMD_COMPLETE_SIZE;
GSList *l;
- char path[MAX_PATH_LENGTH];
- bdaddr_t tmp;
+ char path[MAX_PATH_LENGTH], local_addr[18];
int id;
- baswap(&tmp, local); local_addr = batostr(&tmp);
+ ba2str(local, local_addr);
id = hci_devid(local_addr);
if (id < 0) {
error("No matching device id for %s", local_addr);
- goto failed;
+ return;
}
snprintf(path, sizeof(path), "%s/hci%d", BASE_PATH, id);
@@ -1866,7 +1904,7 @@
if (!dbus_connection_get_object_user_data(connection, path,
(void *) &adapter)) {
error("Getting %s path data failed!", path);
- goto failed;
+ return;
}
l = g_slist_find_custom(adapter->pin_reqs, &ret->bdaddr, pin_req_cmp);
@@ -1874,9 +1912,6 @@
struct pending_pin_info *p = l->data;
p->replied = 1;
}
-
-failed:
- bt_free(local_addr);
}
void create_bond_req_exit(const char *name, struct adapter *adapter)
Modified: bluez-utils/branches/upstream/current/hcid/dbus-hci.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-hci.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-hci.h (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-hci.h Wed Jul 4 13:37:57 2007
@@ -49,6 +49,7 @@
void hcid_dbus_bonding_process_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status);
void hcid_dbus_setname_complete(bdaddr_t *local);
void hcid_dbus_setscan_enable_complete(bdaddr_t *local);
+void hcid_dbus_write_class_complete(bdaddr_t *local);
void hcid_dbus_pin_code_reply(bdaddr_t *local, void *ptr);
int unregister_adapter_path(const char *path);
@@ -72,6 +73,8 @@
name_status_t name_status);
int found_device_req_name(struct adapter *dbus_data);
+int set_limited_discoverable(int dd, const uint8_t *cls, gboolean limited);
+
int discov_timeout_handler(void *data);
void set_dbus_connection(DBusConnection *conn);
Modified: bluez-utils/branches/upstream/current/hcid/dbus-sdp.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-sdp.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-sdp.c (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-sdp.c Wed Jul 4 13:37:57 2007
@@ -65,19 +65,21 @@
#define DEFAULT_XML_BUF_SIZE 1024
typedef struct {
- uint16_t dev_id;
- char *dst;
- void *search_data;
+ uint16_t dev_id;
+ char *dst;
+ void *search_data;
get_record_cb_t *cb;
- void *data;
+ void *data;
} get_record_data_t;
struct transaction_context {
- DBusConnection *conn;
- DBusMessage *rq;
- sdp_session_t *session;
- GIOChannel *io;
- guint io_id;
+ DBusConnection *conn;
+ DBusMessage *rq;
+ sdp_session_t *session;
+ GIOChannel *io;
+ guint io_id;
+ uuid_t uuid;
+ GSList *identifiers;
/* Used for internal async get remote service record implementation */
get_record_data_t *call;
@@ -284,6 +286,7 @@
{ "fax", FAX_SVCLASS_ID, "Fax" },
{ "spp", SERIAL_PORT_SVCLASS_ID, "Serial Port" },
{ "hsp", HEADSET_SVCLASS_ID, "Headset" },
+ { "hfp", HANDSFREE_SVCLASS_ID, "Handsfree" },
{ NULL }
};
@@ -417,6 +420,11 @@
sdp_close(ctxt->session);
g_io_channel_unref(ctxt->io);
+ }
+
+ if (ctxt->identifiers) {
+ g_slist_foreach(ctxt->identifiers, (GFunc) g_free, NULL);
+ g_slist_free(ctxt->identifiers);
}
g_free(ctxt);
@@ -675,7 +683,7 @@
reply = dbus_message_new_method_return(ctxt->rq);
dbus_message_iter_init_append(reply, &iter);
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
- DBUS_TYPE_UINT32_AS_STRING, &array_iter);
+ DBUS_TYPE_UINT32_AS_STRING, &array_iter);
pdata = rsp;
@@ -696,13 +704,187 @@
pdata += sizeof(uint32_t);
dbus_message_iter_append_basic(&array_iter,
- DBUS_TYPE_UINT32, &handle);
+ DBUS_TYPE_UINT32, &handle);
} while (--tsrc);
done:
dbus_message_iter_close_container(&iter, &array_iter);
send_message_and_unref(ctxt->conn, reply);
+
+failed:
+ transaction_context_free(ctxt, TRUE);
+}
+
+static const char *extract_service_class(sdp_data_t *d)
+{
+ sdp_data_t *seq;
+ uuid_t *uuid;
+ static char uuid_str[37];
+
+ /* Expected sequence of UUID16 */
+ if (d->attrId != SDP_ATTR_SVCLASS_ID_LIST || d->dtd != SDP_SEQ8)
+ return NULL;
+
+ if (!d->val.dataseq)
+ return NULL;
+
+ seq = d->val.dataseq;
+ if (!SDP_IS_UUID(seq->dtd))
+ return NULL;
+
+ uuid = &seq->val.uuid;
+ if (uuid->type != SDP_UUID16)
+ return NULL;
+
+ sprintf(uuid_str, "0000%04x-0000-1000-8000-00805f9b34fb",
+ uuid->value.uuid16);
+
+ return uuid_str;
+}
+
+static int service_search_attr(struct transaction_context *ctxt, uint16_t uuid)
+{
+ sdp_list_t *attrids, *search;
+ uint32_t range = 0x0000ffff;
+ int ret = 0;
+
+ sdp_uuid16_create(&ctxt->uuid, uuid);
+
+ search = sdp_list_append(0, &ctxt->uuid);
+ attrids = sdp_list_append(NULL, &range);
+
+ /*
+ * Create/send the search request and set the
+ * callback to indicate the request completion
+ */
+ if (sdp_service_search_attr_async(ctxt->session, search,
+ SDP_ATTR_REQ_RANGE, attrids) < 0)
+ ret = -sdp_get_error(ctxt->session);
+
+ sdp_list_free(search, NULL);
+ sdp_list_free(attrids, NULL);
+
+ return ret;
+}
+
+static void remote_svc_identifiers_completed_cb(uint8_t type, uint16_t err,
+ uint8_t *rsp, size_t size, void *udata)
+{
+ struct transaction_context *ctxt = udata;
+ const char *src, *dst, *puuid;
+ const char *devid_uuid = "00001200-0000-1000-8000-00805f9b34fb";
+ char **identifiers;
+ DBusMessage *reply;
+ GSList *l = NULL;
+ int scanned, extracted = 0, len = 0, recsize = 0;
+ uint8_t dtd = 0;
+
+ if (!ctxt)
+ return;
+
+ if (err == 0xffff) {
+ /* Check for protocol error or I/O error */
+ int sdp_err = sdp_get_error(ctxt->session);
+ if (sdp_err < 0) {
+ error("search failed: Invalid session!");
+ error_failed(ctxt->conn, ctxt->rq, EINVAL);
+ goto failed;
+ }
+
+ error("search failed: %s (%d)", strerror(sdp_err), sdp_err);
+ error_failed(ctxt->conn, ctxt->rq, sdp_err);
+ goto failed;
+ }
+
+ if (type == SDP_ERROR_RSP) {
+ error_sdp_failed(ctxt->conn, ctxt->rq, err);
+ goto failed;
+ }
+
+ /* Check response PDU ID */
+ if (type != SDP_SVC_SEARCH_ATTR_RSP) {
+ error("SDP error: %s (%d)", strerror(EPROTO), EPROTO);
+ error_failed(ctxt->conn, ctxt->rq, EPROTO);
+ goto failed;
+ }
+
+ src = get_address_from_message(ctxt->conn, ctxt->rq);
+ dbus_message_get_args(ctxt->rq, NULL,
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_INVALID);
+
+ scanned = sdp_extract_seqtype(rsp, &dtd, &len);
+ rsp += scanned;
+ for (; extracted < len; rsp += recsize, extracted += recsize) {
+ sdp_record_t *rec;
+ sdp_data_t *d;
+
+ recsize = 0;
+ rec = sdp_extract_pdu(rsp, &recsize);
+ if (!rec)
+ break;
+
+ sdp_store_record(src, dst, rec->handle, rsp, recsize);
+
+ d = sdp_data_get(rec, SDP_ATTR_SVCLASS_ID_LIST);
+ if (!d) {
+ sdp_record_free(rec);
+ continue;
+ }
+
+ puuid = extract_service_class(d);
+ sdp_record_free(rec);
+ if (!puuid)
+ continue;
+
+ /* Ignore repeated identifiers */
+ l = g_slist_find_custom(ctxt->identifiers,
+ puuid, (GCompareFunc) strcmp);
+ if (l)
+ continue;
+
+ ctxt->identifiers = g_slist_append(ctxt->identifiers,
+ g_strdup(puuid));
+ }
+
+ /* If public browse response is empty: search for L2CAP */
+ if (!ctxt->identifiers && ctxt->uuid.value.uuid16 == PUBLIC_BROWSE_GROUP)
+ if (service_search_attr(ctxt, L2CAP_UUID) == 0)
+ return; /* Wait the response */
+
+ /* Request DeviceID if it was not returned previously */
+ l = g_slist_find_custom(ctxt->identifiers,
+ devid_uuid, (GCompareFunc) strcmp);
+ if (!l && ctxt->uuid.value.uuid16 != PNP_INFO_SVCLASS_ID)
+ if (service_search_attr(ctxt, PNP_INFO_SVCLASS_ID) == 0)
+ return; /* Wait the response */
+
+ reply = dbus_message_new_method_return(ctxt->rq);
+
+ identifiers = g_new(char *, g_slist_length(ctxt->identifiers));
+
+ for (l = ctxt->identifiers, len = 0; l; l = l->next, len++)
+ identifiers[len] = l->data;
+
+ dbus_message_append_args(reply,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+ &identifiers, len,
+ DBUS_TYPE_INVALID);
+ send_message_and_unref(ctxt->conn, reply);
+
+ if (len)
+ dbus_connection_emit_signal(ctxt->conn,
+ dbus_message_get_path(ctxt->rq),
+ ADAPTER_INTERFACE,
+ "RemoteIdentifiersUpdated",
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+ &identifiers, len,
+ DBUS_TYPE_INVALID);
+
+ if (identifiers)
+ g_free(identifiers);
failed:
transaction_context_free(ctxt, TRUE);
@@ -882,6 +1064,9 @@
int err;
connect_cb_t *cb;
+ if (!adapter->up)
+ return error_not_ready(conn, msg);
+
if (!dbus_message_get_args(msg, NULL,
DBUS_TYPE_STRING, &dst,
DBUS_TYPE_UINT32, &handle,
@@ -908,7 +1093,6 @@
{
sdp_list_t *search = NULL;
const char *dst, *svc;
- uuid_t uuid;
if (sdp_set_notify(ctxt->session, remote_svc_handles_completed_cb, ctxt) < 0)
return -EINVAL;
@@ -919,11 +1103,11 @@
DBUS_TYPE_INVALID);
if (strlen(svc) > 0)
- str2uuid(&uuid, svc);
+ str2uuid(&ctxt->uuid, svc);
else
- sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
-
- search = sdp_list_append(0, &uuid);
+ sdp_uuid16_create(&ctxt->uuid, PUBLIC_BROWSE_GROUP);
+
+ search = sdp_list_append(0, &ctxt->uuid);
/* Create/send the search request and set the callback to indicate the request completion */
if (sdp_service_search_async(ctxt->session, search, 64) < 0) {
@@ -937,12 +1121,24 @@
return 0;
}
+static int remote_svc_identifiers_conn_cb(struct transaction_context *ctxt)
+{
+ if (sdp_set_notify(ctxt->session,
+ remote_svc_identifiers_completed_cb, ctxt) < 0)
+ return -EINVAL;
+
+ return service_search_attr(ctxt, PUBLIC_BROWSE_GROUP);
+}
+
DBusHandlerResult get_remote_svc_handles(DBusConnection *conn, DBusMessage *msg, void *data)
{
struct adapter *adapter = data;
const char *dst, *svc;
int err;
uuid_t uuid;
+
+ if (!adapter->up)
+ return error_not_ready(conn, msg);
if (!dbus_message_get_args(msg, NULL,
DBUS_TYPE_STRING, &dst,
@@ -963,6 +1159,32 @@
if (!connect_request(conn, msg, adapter->dev_id,
dst, remote_svc_handles_conn_cb, &err)) {
+ error("Search request failed: %s (%d)", strerror(err), err);
+ return error_failed(conn, msg, err);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+DBusHandlerResult get_remote_svc_identifiers(DBusConnection *conn, DBusMessage *msg, void *data)
+{
+ struct adapter *adapter = data;
+ const char *dst;
+ int err;
+
+ if (!adapter->up)
+ return error_not_ready(conn, msg);
+
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &dst,
+ DBUS_TYPE_INVALID))
+ return error_invalid_arguments(conn, msg);
+
+ if (find_pending_connect(dst))
+ return error_service_search_in_progress(conn, msg);
+
+ if (!connect_request(conn, msg, adapter->dev_id,
+ dst, remote_svc_identifiers_conn_cb, &err)) {
error("Search request failed: %s (%d)", strerror(err), err);
return error_failed(conn, msg, err);
}
Modified: bluez-utils/branches/upstream/current/hcid/dbus-sdp.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-sdp.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-sdp.h (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-sdp.h Wed Jul 4 13:37:57 2007
@@ -35,6 +35,8 @@
DBusHandlerResult get_remote_svc_handles(DBusConnection *conn, DBusMessage *msg, void *data);
+DBusHandlerResult get_remote_svc_identifiers(DBusConnection *conn, DBusMessage *msg, void *data);
+
DBusHandlerResult get_remote_svc_rec(DBusConnection *conn, DBusMessage *msg, void *data, sdp_format_t format);
DBusHandlerResult finish_remote_svc_transact(DBusConnection *conn, DBusMessage *msg, void *data);
Modified: bluez-utils/branches/upstream/current/hcid/dbus-service.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-service.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-service.c (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-service.c Wed Jul 4 13:37:57 2007
@@ -43,6 +43,7 @@
#include "dbus-helper.h"
#include "hcid.h"
#include "notify.h"
+#include "server.h"
#include "dbus-common.h"
#include "dbus-error.h"
#include "dbus-manager.h"
@@ -408,7 +409,7 @@
int service_start(struct service *service, DBusConnection *conn)
{
DBusError derr;
- char *argv[2], command[PATH_MAX];
+ char *addr, *argv[2], *envp[2], command[PATH_MAX], address[256];
if (!dbus_connection_add_filter(conn, service_filter, service, NULL)) {
error("Unable to add signal filter");
@@ -425,11 +426,19 @@
}
snprintf(command, sizeof(command) - 1, "%s/bluetoothd-service-%s",
- SERVICEDIR, service->ident);
+ SERVICEDIR, service->ident);
argv[0] = command;
argv[1] = NULL;
- if (!g_spawn_async(SERVICEDIR, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
+ addr = get_local_server_address();
+
+ snprintf(address, sizeof(address) - 1, "BLUETOOTHD_ADDRESS=%s", addr);
+ envp[0] = address;
+ envp[1] = NULL;
+
+ dbus_free(addr);
+
+ if (!g_spawn_async(SERVICEDIR, argv, envp, G_SPAWN_DO_NOT_REAP_CHILD,
service_setup, service, &service->pid, NULL)) {
error("Unable to execute %s", argv[0]);
dbus_connection_remove_filter(conn, service_filter, service);
@@ -718,7 +727,8 @@
return 0;
}
-static int unregister_service(struct service *service)
+static int unregister_service_for_connection(DBusConnection *connection,
+ struct service *service)
{
DBusConnection *conn = get_dbus_connection();
@@ -728,7 +738,7 @@
goto cleanup;
if (service->bus_name)
- name_listener_remove(conn, service->bus_name,
+ name_listener_remove(connection, service->bus_name,
(name_cb_t) service_exit, service);
dbus_connection_emit_signal(conn, service->object_path,
@@ -759,6 +769,11 @@
}
return 0;
+}
+
+static int unregister_service(struct service *service)
+{
+ return unregister_service_for_connection(get_dbus_connection(), service);
}
void release_services(DBusConnection *conn)
@@ -1021,10 +1036,9 @@
service_free(service);
}
-int service_register(const char *bus_name, const char *ident,
+int service_register(DBusConnection *conn, const char *bus_name, const char *ident,
const char *name, const char *description)
{
- DBusConnection *conn = get_dbus_connection();
struct service *service;
if (!conn)
@@ -1044,14 +1058,14 @@
name_listener_add(conn, bus_name, (name_cb_t) external_service_exit,
service);
- dbus_connection_emit_signal(conn, service->object_path,
+ dbus_connection_emit_signal(get_dbus_connection(), service->object_path,
SERVICE_INTERFACE, "Started",
DBUS_TYPE_INVALID);
return 0;
}
-int service_unregister(struct service *service)
-{
- return unregister_service(service);
-}
+int service_unregister(DBusConnection *conn, struct service *service)
+{
+ return unregister_service_for_connection(conn, service);
+}
Modified: bluez-utils/branches/upstream/current/hcid/dbus-service.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/dbus-service.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/dbus-service.h (original)
+++ bluez-utils/branches/upstream/current/hcid/dbus-service.h Wed Jul 4 13:37:57 2007
@@ -59,9 +59,9 @@
int init_services(const char *path);
-int service_register(const char *bus_name, const char *ident,
+int service_register(DBusConnection *conn, const char *bus_name, const char *ident,
const char *name, const char *description);
-int service_unregister(struct service *service);
+int service_unregister(DBusConnection *conn, struct service *service);
#endif /* __BLUEZ_DBUS_SERVICE_H */
Modified: bluez-utils/branches/upstream/current/hcid/device.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/device.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/device.c (original)
+++ bluez-utils/branches/upstream/current/hcid/device.c Wed Jul 4 13:37:57 2007
@@ -81,6 +81,7 @@
uint16_t manufacturer;
uint8_t name[248];
+ uint8_t class[3];
struct hci_peer *peers;
struct hci_conn *conns;
@@ -203,7 +204,8 @@
struct hci_dev *dev;
struct hci_version ver;
uint8_t features[8], inqmode;
- int dd;
+ uint8_t events[8] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00 };
+ int dd, err;
ASSERT_DEV_ID;
@@ -233,14 +235,22 @@
dev->manufacturer = ver.manufacturer;
if (hci_read_local_features(dd, features, 1000) < 0) {
- int err = errno;
+ err = errno;
error("Can't read features for hci%d: %s (%d)",
- dev_id, strerror(errno), errno);
+ dev_id, strerror(err), err);
hci_close_dev(dd);
return -err;
}
memcpy(dev->features, features, 8);
+
+ if (hci_read_class_of_dev(dd, dev->class, 1000) < 0) {
+ err = errno;
+ error("Can't read class of device on hci%d: %s(%d)",
+ dev_id, strerror(err), err);
+ hci_close_dev(dd);
+ return -err;
+ }
inqmode = get_inquiry_mode(dev);
if (inqmode < 1)
@@ -254,6 +264,26 @@
return -err;
}
+ if (ver.hci_rev > 1) {
+ if (features[5] & LMP_SNIFF_SUBR)
+ events[5] |= 0x20;
+
+ if (features[5] & LMP_PAUSE_ENC)
+ events[5] |= 0x80;
+
+ if (features[6] & LMP_EXT_INQ)
+ events[5] |= 0x40;
+
+ if (features[6] & LMP_NFLUSH_PKTS)
+ events[7] |= 0x01;
+
+ if (features[7] & LMP_LSTO)
+ events[6] |= 0x80;
+
+ hci_send_cmd(dd, OGF_HOST_CTL, OCF_SET_EVENT_MASK,
+ sizeof(events), events);
+ }
+
done:
hci_close_dev(dd);
@@ -283,6 +313,18 @@
dev = &devices[dev_id];
return ba2str(&dev->bdaddr, address);
+}
+
+int get_device_class(uint16_t dev_id, uint8_t *cls)
+{
+ struct hci_dev *dev;
+
+ ASSERT_DEV_ID;
+
+ dev = &devices[dev_id];
+ memcpy(cls, dev->class, 3);
+
+ return 0;
}
int get_device_version(uint16_t dev_id, char *version, size_t size)
Modified: bluez-utils/branches/upstream/current/hcid/hcid.8
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/hcid.8?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/hcid.8 (original)
+++ bluez-utils/branches/upstream/current/hcid/hcid.8 Wed Jul 4 13:37:57 2007
@@ -34,6 +34,9 @@
.TP
.BI \-s
Enable internal SDP server.
+.TP
+.BI \-m\ mtu\-size
+Use specific MTU size for SDP server.
.TP
.BI \-f\ config\-file
Use alternate configuration file instead of /etc/bluetooth/hcid.conf
Modified: bluez-utils/branches/upstream/current/hcid/hcid.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/hcid.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/hcid.h (original)
+++ bluez-utils/branches/upstream/current/hcid/hcid.h Wed Jul 4 13:37:57 2007
@@ -39,19 +39,6 @@
/* When all services should trust a remote device */
#define GLOBAL_TRUST "[all]"
-
-/*
- * Scanning modes, used by DEV_SET_MODE
- * off: remote devices are not allowed to find or connect to this device
- * connectable: remote devices are allowed to connect, but they are not
- * allowed to find it.
- * discoverable: remote devices are allowed to connect and find this device
- * unknown: reserved to not allowed/future modes
- */
-#define MODE_OFF "off"
-#define MODE_CONNECTABLE "connectable"
-#define MODE_DISCOVERABLE "discoverable"
-#define MODE_UNKNOWN "unknown"
enum {
HCID_SET_NAME,
@@ -64,6 +51,22 @@
HCID_SET_LM,
HCID_SET_LP,
};
+
+/*
+ * Scanning modes, used by DEV_SET_MODE
+ * off: remote devices are not allowed to find or connect to this device
+ * connectable: remote devices are allowed to connect, but they are not
+ * allowed to find it.
+ * discoverable: remote devices are allowed to connect and find this device
+ * limited: limited discoverable - GIAC + IAC enabled and set limited
+ * bit on device class.
+ */
+
+#define MODE_OFF 0x00
+#define MODE_CONNECTABLE 0x01
+#define MODE_DISCOVERABLE 0x02
+#define MODE_LIMITED 0x03
+#define MODE_UNKNOWN 0xff
struct device_opts {
unsigned long flags;
@@ -76,6 +79,7 @@
uint16_t link_mode;
uint16_t link_policy;
uint8_t scan;
+ uint8_t mode;
uint32_t discovto;
};
@@ -140,6 +144,7 @@
struct device_opts *alloc_device_opts(char *ref);
+uint8_t get_startup_scan(int hdev);
uint8_t get_startup_mode(int hdev);
int get_discoverable_timeout(int dev_id);
@@ -157,6 +162,7 @@
int stop_device(uint16_t dev_id);
int get_device_address(uint16_t dev_id, char *address, size_t size);
+int get_device_class(uint16_t dev_id, uint8_t *class);
int get_device_version(uint16_t dev_id, char *version, size_t size);
int get_device_revision(uint16_t dev_id, char *revision, size_t size);
int get_device_manufacturer(uint16_t dev_id, char *manufacturer, size_t size);
Modified: bluez-utils/branches/upstream/current/hcid/main.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/main.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/main.c (original)
+++ bluez-utils/branches/upstream/current/hcid/main.c Wed Jul 4 13:37:57 2007
@@ -50,6 +50,7 @@
#include "hcid.h"
#include "sdpd.h"
+#include "server.h"
#include "dbus-common.h"
#include "dbus-service.h"
#include "dbus-database.h"
@@ -65,6 +66,7 @@
{
memset(device_opts, 0, sizeof(*device_opts));
device_opts->scan = SCAN_PAGE;
+ device_opts->mode = MODE_CONNECTABLE;
device_opts->name = g_strdup("BlueZ");
device_opts->discovto = HCID_DEFAULT_DISCOVERABLE_TIMEOUT;
}
@@ -143,7 +145,7 @@
return device_opts;
}
-uint8_t get_startup_mode(int hdev)
+static struct device_opts *get_opts(int hdev)
{
struct device_opts *device_opts = NULL;
struct hci_dev_info di;
@@ -151,7 +153,7 @@
int sock;
if (hdev < 0)
- return SCAN_DISABLED;
+ return NULL;
sock = hci_open_dev(hdev);
if (sock < 0)
@@ -177,7 +179,25 @@
if (!device_opts)
device_opts = &default_device;
+ return device_opts;
+}
+
+uint8_t get_startup_scan(int hdev)
+{
+ struct device_opts *device_opts = get_opts(hdev);
+ if (!device_opts)
+ return SCAN_DISABLED;
+
return device_opts->scan;
+}
+
+uint8_t get_startup_mode(int hdev)
+{
+ struct device_opts *device_opts = get_opts(hdev);
+ if (!device_opts)
+ return MODE_OFF;
+
+ return device_opts->mode;
}
int get_discoverable_timeout(int hdev)
@@ -326,16 +346,30 @@
/* Set scan mode */
if (read_device_mode(&di.bdaddr, mode, sizeof(mode)) == 0) {
- if (!strcmp(mode, MODE_OFF) && hcid.offmode == HCID_OFFMODE_NOSCAN)
+ if (!strcmp(mode, "off") && hcid.offmode == HCID_OFFMODE_NOSCAN) {
+ device_opts->mode = MODE_OFF;
device_opts->scan = SCAN_DISABLED;
- else if (!strcmp(mode, MODE_CONNECTABLE))
+ } else if (!strcmp(mode, "connectable")) {
+ device_opts->mode = MODE_CONNECTABLE;
device_opts->scan = SCAN_PAGE;
- else if (!strcmp(mode, MODE_DISCOVERABLE)) {
+ } else if (!strcmp(mode, "discoverable")) {
/* Set discoverable only if timeout is 0 */
- if (!get_discoverable_timeout(dev_id))
+ if (!get_discoverable_timeout(dev_id)) {
device_opts->scan = SCAN_PAGE | SCAN_INQUIRY;
- else
+ device_opts->mode = MODE_DISCOVERABLE;
+ } else {
device_opts->scan = SCAN_PAGE;
+ device_opts->mode = MODE_CONNECTABLE;
+ }
+ } else if (!strcmp(mode, "limited")) {
+ /* Set discoverable only if timeout is 0 */
+ if (!get_discoverable_timeout(dev_id)) {
+ device_opts->scan = SCAN_PAGE | SCAN_INQUIRY;
+ device_opts->mode = MODE_LIMITED;
+ } else {
+ device_opts->scan = SCAN_PAGE;
+ device_opts->mode = MODE_CONNECTABLE;
+ }
}
}
@@ -431,9 +465,11 @@
if (read_local_class(&di.bdaddr, cls) < 0) {
class = htobl(device_opts->class);
memcpy(cp.dev_class, &class, 3);
- } else
+ } else {
+ if (!(device_opts->scan & SCAN_INQUIRY))
+ cls[1] &= 0xdf; /* Clear discoverable bit */
memcpy(cp.dev_class, cls, 3);
-
+ }
hci_send_cmd(dd, OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV,
WRITE_CLASS_OF_DEV_CP_SIZE, &cp);
}
@@ -500,7 +536,7 @@
char mode[16];
if (read_device_mode(&di.bdaddr, mode, sizeof(mode)) == 0 &&
- strcmp(mode, MODE_OFF) == 0) {
+ strcmp(mode, "off") == 0) {
ioctl(dd, HCIDEVDOWN, dev_id);
exit(0);
}
@@ -675,7 +711,7 @@
{
printf("hcid - HCI daemon ver %s\n", VERSION);
printf("Usage: \n");
- printf("\thcid [-n] [-d] [-s] [-f config file]\n");
+ printf("\thcid [-n] [-d] [-s] [-m mtu] [-f config file]\n");
}
int main(int argc, char *argv[])
@@ -684,6 +720,7 @@
struct hci_filter flt;
struct sigaction sa;
GIOChannel *ctl_io, *child_io;
+ uint16_t mtu = 0;
int opt, daemonize = 1, debug = 0, sdp = 0, experimental = 0;
/* Default HCId settings */
@@ -702,7 +739,7 @@
init_defaults();
- while ((opt = getopt(argc, argv, "ndsxf:")) != EOF) {
+ while ((opt = getopt(argc, argv, "ndsm:xf:")) != EOF) {
switch (opt) {
case 'n':
daemonize = 0;
@@ -714,6 +751,10 @@
case 's':
sdp = 1;
+ break;
+
+ case 'm':
+ mtu = atoi(optarg);
break;
case 'x':
@@ -825,10 +866,12 @@
if (sdp) {
set_sdp_server_enable();
- start_sdp_server(0, hcid.deviceid, SDP_SERVER_COMPAT);
+ start_sdp_server(mtu, hcid.deviceid, SDP_SERVER_COMPAT);
}
notify_init();
+
+ init_local_server();
init_services(CONFIGDIR);
@@ -844,6 +887,8 @@
notify_close();
+ shutdown_local_server();
+
cleanup_sdp_session();
g_main_loop_unref(event_loop);
Modified: bluez-utils/branches/upstream/current/hcid/security.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/security.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/security.c (original)
+++ bluez-utils/branches/upstream/current/hcid/security.c Wed Jul 4 13:37:57 2007
@@ -436,6 +436,9 @@
case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):
hcid_dbus_setscan_enable_complete(sba);
break;
+ case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV):
+ hcid_dbus_write_class_complete(sba);
+ break;
case cmd_opcode_pack(OGF_LINK_CTL, OCF_PIN_CODE_REPLY):
case cmd_opcode_pack(OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY):
hcid_dbus_pin_code_reply(sba, ptr);
@@ -582,9 +585,11 @@
evt_conn_complete *evt = ptr;
char filename[PATH_MAX];
remote_name_req_cp cp_name;
- bdaddr_t tmp;
struct hci_req_data *data;
- char *str, *local_addr, *peer_addr;
+ char local_addr[18], peer_addr[18], *str;
+
+ if (evt->link_type != ACL_LINK)
+ return;
hcid_dbus_conn_complete(sba, evt->status, evt->handle, &evt->bdaddr);
@@ -605,8 +610,8 @@
hci_req_queue_append(data);
/* check if the remote version needs be requested */
- baswap(&tmp, sba); local_addr = batostr(&tmp);
- baswap(&tmp, &evt->bdaddr); peer_addr = batostr(&tmp);
+ ba2str(sba, local_addr);
+ ba2str(&evt->bdaddr, peer_addr);
create_name(filename, sizeof(filename), STORAGEDIR, local_addr, "manufacturers");
@@ -623,9 +628,6 @@
hci_req_queue_append(data);
} else
free(str);
-
- free(local_addr);
- free(peer_addr);
}
static inline void disconn_complete(int dev, bdaddr_t *sba, void *ptr)
Added: bluez-utils/branches/upstream/current/hcid/server.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/server.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/server.c (added)
+++ bluez-utils/branches/upstream/current/hcid/server.c Wed Jul 4 13:37:57 2007
@@ -1,0 +1,136 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <dbus.h>
+
+#include "dbus-database.h"
+
+#include "logging.h"
+#include "server.h"
+
+static DBusHandlerResult filter_function(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ if (dbus_message_is_signal(msg, DBUS_INTERFACE_LOCAL, "Disconnected") &&
+ strcmp(dbus_message_get_path(msg), DBUS_PATH_LOCAL) == 0) {
+ debug("Received local disconnected signal");
+ name_listener_indicate_disconnect(conn);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult message_handler(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ if (strcmp(dbus_message_get_interface(msg), DATABASE_INTERFACE) == 0)
+ return database_message(conn, msg, data);
+
+ debug("%s -> %s.%s", dbus_message_get_path(msg),
+ dbus_message_get_interface(msg), dbus_message_get_member(msg));
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void unregister_handler(DBusConnection *conn, void *data)
+{
+ debug("Unregister local connection %p", conn);
+}
+
+static void handle_connection(DBusServer *server, DBusConnection *conn, void *data)
+{
+ DBusObjectPathVTable vtable = { &unregister_handler, &message_handler,
+ NULL, NULL, NULL, NULL};
+
+ debug("New local connection %p", conn);
+
+ dbus_connection_add_filter(conn, filter_function, NULL, NULL);
+
+ if (dbus_connection_register_object_path(conn, "/org/bluez",
+ &vtable, NULL) == FALSE) {
+ error("Can't register local object path");
+ return;
+ }
+
+ dbus_connection_ref(conn);
+
+ //dbus_connection_setup_with_g_main(conn, NULL);
+ setup_dbus_with_main_loop(conn);
+}
+
+static DBusServer *server = NULL;
+
+char *get_local_server_address(void)
+{
+ return dbus_server_get_address(server);
+}
+
+void init_local_server(void)
+{
+ const char *ext_only[] = { "EXTERNAL", NULL };
+ char *address;
+ DBusError err;
+
+ dbus_error_init(&err);
+
+ server = dbus_server_listen("unix:tmpdir=/var/run", &err);
+ if (server == NULL) {
+ error("Can't create local D-Bus server");
+ dbus_error_free(&err);
+ return;
+ }
+
+ address = dbus_server_get_address(server);
+
+ info("Created local server at %s", address);
+
+ dbus_free(address);
+
+ //dbus_server_setup_with_g_main(server, NULL);
+ setup_dbus_server_with_main_loop(server);
+
+ dbus_server_set_new_connection_function(server, handle_connection,
+ NULL, NULL);
+
+ dbus_server_set_auth_mechanisms(server, ext_only);
+}
+
+void shutdown_local_server(void)
+{
+ if (server == NULL)
+ return;
+
+ info("Shutting down local server");
+
+ dbus_server_disconnect(server);
+
+ dbus_server_unref(server);
+
+ server = NULL;
+}
Added: bluez-utils/branches/upstream/current/hcid/server.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/hcid/server.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/hcid/server.h (added)
+++ bluez-utils/branches/upstream/current/hcid/server.h Wed Jul 4 13:37:57 2007
@@ -1,0 +1,27 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+void init_local_server(void);
+void shutdown_local_server(void);
+
+char *get_local_server_address(void);
Modified: bluez-utils/branches/upstream/current/input/device.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/input/device.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/input/device.c (original)
+++ bluez-utils/branches/upstream/current/input/device.c Wed Jul 4 13:37:57 2007
@@ -59,11 +59,6 @@
#define UPDOWN_ENABLED 1
-struct pending_connect {
- DBusConnection *conn;
- DBusMessage *msg;
-};
-
struct fake_input {
GIOChannel *io;
int rfcomm; /* RFCOMM socket */
@@ -77,10 +72,18 @@
char *name;
uint8_t major;
uint8_t minor;
- struct hidp_connadd_req hidp; /* FIXME: Use dynamic alloc? */
+ uint16_t product;
+ uint16_t vendor;
struct fake_input *fake;
- struct pending_connect *pending_connect;
+ DBusMessage *pending_connect;
+ DBusConnection *conn;
+ char *path;
+ int ctrl_sk;
+ int intr_sk;
+ guint watch;
};
+
+GSList *devices = NULL;
static struct device *device_new(bdaddr_t *src, bdaddr_t *dst)
{
@@ -95,24 +98,12 @@
read_device_name(src, dst, &idev->name);
read_device_class(src, dst, &cls);
- idev->major = (cls >> 8) & 0x1f;
- idev->minor = (cls >> 2) & 0x3f;
-
- /* FIXME: hidp could be alloc dynamically */
- snprintf(idev->hidp.name, 128, "%s", idev->name);
+ idev->major = (cls >> 8) & 0x1f;
+ idev->minor = (cls >> 2) & 0x3f;
+ idev->ctrl_sk = -1;
+ idev->intr_sk = -1;
return idev;
-}
-
-static void pending_connect_free(struct pending_connect *pc)
-{
- if (!pc)
- return;
- if (pc->conn)
- dbus_connection_unref(pc->conn);
- if (pc->msg)
- dbus_message_unref(pc->msg);
- g_free(pc);
}
static void device_free(struct device *idev)
@@ -121,13 +112,13 @@
return;
if (idev->name)
g_free(idev->name);
- if (idev->hidp.rd_data)
- g_free(idev->hidp.rd_data);
if (idev->fake)
g_free(idev->fake);
- if (idev->pending_connect)
- pending_connect_free(idev->pending_connect);
-
+ if (idev->path)
+ g_free(idev->path);
+ if (idev->pending_connect)
+ dbus_message_unref(idev->pending_connect);
+ dbus_connection_unref(idev->conn);
g_free(idev);
}
@@ -416,24 +407,24 @@
(GIOFunc) rfcomm_io_cb, fake);
/* Replying to the requestor */
- reply = dbus_message_new_method_return(idev->pending_connect->msg);
- send_message_and_unref(idev->pending_connect->conn, reply);
+ reply = dbus_message_new_method_return(idev->pending_connect);
+ send_message_and_unref(idev->conn, reply);
/* Sending the Connected signal */
- path = dbus_message_get_path(idev->pending_connect->msg);
- dbus_connection_emit_signal(idev->pending_connect->conn, path,
+ path = dbus_message_get_path(idev->pending_connect);
+ dbus_connection_emit_signal(idev->conn, path,
INPUT_DEVICE_INTERFACE, "Connected",
DBUS_TYPE_INVALID);
- pending_connect_free(idev->pending_connect);
+ dbus_message_unref(idev->pending_connect);
idev->pending_connect = NULL;
return FALSE;
failed:
- err_connection_failed(idev->pending_connect->conn,
- idev->pending_connect->msg, strerror(err));
- pending_connect_free(idev->pending_connect);
+ err_connection_failed(idev->conn,
+ idev->pending_connect, strerror(err));
+ dbus_message_unref(idev->pending_connect);
idev->pending_connect = NULL;
g_io_channel_close(chan);
@@ -509,11 +500,100 @@
return -err;
}
+static gboolean connection_event(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+ struct device *idev = data;
+ gboolean ret = TRUE;
+
+ if (cond & G_IO_NVAL)
+ ret = FALSE;
+
+ if (cond & (G_IO_HUP | G_IO_ERR)) {
+ g_io_channel_close(chan);
+ ret = FALSE;
+ }
+
+ if (ret == FALSE) {
+ dbus_connection_emit_signal(idev->conn,
+ idev->path,
+ INPUT_DEVICE_INTERFACE,
+ "Disconnected",
+ DBUS_TYPE_INVALID);
+ idev->watch = 0;
+ }
+
+ return ret;
+}
+
+static guint create_watch(int sk, struct device *idev)
+{
+ guint id;
+ GIOChannel *io;
+
+ io = g_io_channel_unix_new(sk);
+ id = g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ connection_event, idev);
+ g_io_channel_unref(io);
+
+ return id;
+}
+
+static int hidp_connadd(bdaddr_t *src, bdaddr_t *dst, int ctrl_sk, int intr_sk, const char *name)
+{
+ struct hidp_connadd_req req;
+ char addr[18];
+ int ctl, err, timeout = 30;
+
+ ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
+ if (ctl < 0) {
+ error("Can't open HIDP interface");
+ return -errno;
+ }
+
+ ba2str(dst, addr);
+
+ memset(&req, 0, sizeof(req));
+ req.ctrl_sock = ctrl_sk;
+ req.intr_sock = intr_sk;
+ req.flags = 0;
+ req.idle_to = timeout * 60;
+
+ err = get_stored_device_info(src, dst, &req);
+ if (err < 0) {
+ error("Rejected connection from unknown device %s", addr);
+ goto cleanup;
+ }
+
+ if (req.subclass & 0x40) {
+ err = encrypt_link(src, dst);
+ if (err < 0 && err != -ENOKEY)
+ goto cleanup;
+ }
+
+ if (name)
+ strncpy(req.name, name, 128);
+
+ info("New input device %s (%s)", addr, req.name);
+
+ if (req.vendor == 0x054c && req.product == 0x0268) {
+ unsigned char buf[] = { 0x53, 0xf4, 0x42, 0x03, 0x00, 0x00 };
+ err = write(ctrl_sk, buf, sizeof(buf));
+ }
+
+ err = ioctl(ctl, HIDPCONNADD, &req);
+cleanup:
+ close(ctl);
+
+ if (req.rd_data)
+ free(req.rd_data);
+
+ return err;
+}
+
static gboolean interrupt_connect_cb(GIOChannel *chan,
GIOCondition cond, struct device *idev)
{
- int ctl, isk, ret, err;
- const char *path;
+ int isk, ret, err;
socklen_t len;
isk = g_io_channel_unix_get_fd(chan);
@@ -530,9 +610,6 @@
goto failed;
}
-
- idev->hidp.intr_sock = isk;
- idev->hidp.idle_to = 30 * 60; /* 30 minutes */
len = sizeof(ret);
if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) {
@@ -547,55 +624,34 @@
goto failed;
}
- ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
- if (ctl < 0) {
- err = errno;
- error("Can't open HIDP control socket");
- goto failed;
- }
-
- if (idev->hidp.subclass & 0x40) {
- int ret;
- ret = encrypt_link(&idev->src, &idev->dst);
- if (ret < 0 && ret != -ENOKEY) {
- err = -ret;
- close(ctl);
- goto failed;
- }
- }
-
- if (ioctl(ctl, HIDPCONNADD, &idev->hidp) < 0) {
- err = errno;
- close(ctl);
- goto failed;
- }
+ idev->intr_sk = isk;
+ err = hidp_connadd(&idev->src, &idev->dst, idev->ctrl_sk, idev->intr_sk, idev->name);
+ if (err < 0)
+ goto failed;
+
+ idev->watch = create_watch(idev->ctrl_sk, idev);
+ dbus_connection_emit_signal(idev->conn,
+ idev->path,
+ INPUT_DEVICE_INTERFACE,
+ "Connected",
+ DBUS_TYPE_INVALID);
/* Replying to the requestor */
- send_message_and_unref(idev->pending_connect->conn,
- dbus_message_new_method_return(idev->pending_connect->msg));
-
- /* Sending the Connected signal */
- path = dbus_message_get_path(idev->pending_connect->msg);
- dbus_connection_emit_signal(idev->pending_connect->conn, path,
- INPUT_DEVICE_INTERFACE, "Connected" ,
- DBUS_TYPE_INVALID);
-
- close (ctl);
+ send_message_and_unref(idev->conn,
+ dbus_message_new_method_return(idev->pending_connect));
+
goto cleanup;
failed:
- err_connection_failed(idev->pending_connect->conn,
- idev->pending_connect->msg, strerror(err));
-
-cleanup:
+ err_connection_failed(idev->conn,
+ idev->pending_connect, strerror(err));
if (isk > 0)
close(isk);
-
- close(idev->hidp.ctrl_sock);
-
- idev->hidp.intr_sock = -1;
- idev->hidp.ctrl_sock = -1;
-
- pending_connect_free(idev->pending_connect);
+ close(idev->ctrl_sk);
+ idev->intr_sk = -1;
+ idev->ctrl_sk = -1;
+
+cleanup:
+ dbus_message_unref(idev->pending_connect);
idev->pending_connect = NULL;
return FALSE;
@@ -622,7 +678,7 @@
}
/* Set HID control channel */
- idev->hidp.ctrl_sock = csk;
+ idev->ctrl_sk = csk;
len = sizeof(ret);
if (getsockopt(csk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) {
@@ -652,10 +708,10 @@
if (csk > 0)
close(csk);
- idev->hidp.ctrl_sock = -1;
- err_connection_failed(idev->pending_connect->conn,
- idev->pending_connect->msg, strerror(err));
- pending_connect_free(idev->pending_connect);
+ idev->ctrl_sk = -1;
+ err_connection_failed(idev->conn,
+ idev->pending_connect, strerror(err));
+ dbus_message_unref(idev->pending_connect);
idev->pending_connect = NULL;
return FALSE;
@@ -687,6 +743,14 @@
}
/* Standard HID disconnect */
+ if (idev->ctrl_sk >= 0) {
+ close(idev->ctrl_sk);
+ idev->ctrl_sk = -1;
+ }
+ if (idev->intr_sk >= 0) {
+ close(idev->intr_sk);
+ idev->intr_sk = -1;
+ }
ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
if (ctl < 0) {
@@ -719,9 +783,6 @@
close(ctl);
errno = err;
- idev->hidp.intr_sock = -1;
- idev->hidp.ctrl_sock = -1;
-
return -err;
}
@@ -773,21 +834,14 @@
if (is_connected(idev))
return err_already_connected(conn, msg);
- idev->pending_connect = g_try_new0(struct pending_connect, 1);
- if (!idev->pending_connect) {
- error("Out of memory when allocating new struct pending_connect");
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
- }
-
- idev->pending_connect->conn = dbus_connection_ref(conn);
- idev->pending_connect->msg = dbus_message_ref(msg);
+ idev->pending_connect = dbus_message_ref(msg);
/* Fake input device */
if (idev->fake) {
if (rfcomm_connect(idev) < 0) {
const char *str = strerror(errno);
error("RFCOMM connect failed: %s(%d)", str, errno);
- pending_connect_free(idev->pending_connect);
+ dbus_message_unref(idev->pending_connect);
idev->pending_connect = NULL;
return err_connection_failed(conn, msg, str);
}
@@ -797,11 +851,10 @@
/* HID devices */
if (l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL,
(GIOFunc) control_connect_cb, idev) < 0) {
-
int err = errno;
error("L2CAP connect failed: %s(%d)", strerror(err), err);
- pending_connect_free(idev->pending_connect);
+ dbus_message_unref(idev->pending_connect);
idev->pending_connect = NULL;
return err_connection_failed(conn, msg, strerror(err));
}
@@ -813,22 +866,13 @@
DBusMessage *msg, void *data)
{
struct device *idev = data;
- const char *path;
if (disconnect(idev, 0) < 0)
return err_failed(conn, msg, strerror(errno));
/* Replying to the requestor */
- send_message_and_unref(conn,
+ return send_message_and_unref(conn,
dbus_message_new_method_return(msg));
-
- /* Sending the Disconnect signal */
- path = dbus_message_get_path(msg);
- dbus_connection_emit_signal(conn, path,
- INPUT_DEVICE_INTERFACE, "Disconnected",
- DBUS_TYPE_INVALID);
-
- return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult device_is_connected(DBusConnection *conn,
@@ -897,7 +941,7 @@
{
struct device *idev = data;
DBusMessage *reply;
- const char *pname = idev->hidp.name;
+ const char *pname = idev->name;
reply = dbus_message_new_method_return(msg);
if (!reply)
@@ -921,7 +965,7 @@
return DBUS_HANDLER_RESULT_NEED_MEMORY;
dbus_message_append_args(reply,
- DBUS_TYPE_UINT16, &idev->hidp.product,
+ DBUS_TYPE_UINT16, &idev->product,
DBUS_TYPE_INVALID);
return send_message_and_unref(conn, reply);
@@ -938,7 +982,7 @@
return DBUS_HANDLER_RESULT_NEED_MEMORY;
dbus_message_append_args(reply,
- DBUS_TYPE_UINT16, &idev->hidp.vendor,
+ DBUS_TYPE_UINT16, &idev->vendor,
DBUS_TYPE_INVALID);
return send_message_and_unref(conn, reply);
@@ -995,7 +1039,9 @@
dbus_connection_emit_signal(conn, INPUT_PATH,
INPUT_MANAGER_INTERFACE, "DeviceCreated",
DBUS_TYPE_STRING, &path,
- DBUS_TYPE_INVALID);
+ DBUS_TYPE_INVALID);
+
+ devices = g_slist_append(devices, idev);
info("Created input device: %s", path);
@@ -1011,9 +1057,10 @@
idev = device_new(src, dst);
path = create_input_path(idev->major, idev->minor);
-
- /* rd_data must not be deallocated since the memory address is copied */
- memcpy(&idev->hidp, hid, sizeof(struct hidp_connadd_req));
+ idev->path = g_strdup(path);
+ idev->product = hid->product;
+ idev->vendor = hid->vendor;
+ idev->conn = dbus_connection_ref(conn);
err = register_path(conn, path, idev);
@@ -1032,6 +1079,10 @@
idev = device_new(src, dst);
path = create_input_path(idev->major, idev->minor);
+ idev->path = g_strdup(path);
+ idev->conn = dbus_connection_ref(conn);
+
+ /* FIXME: Missing set product and vendor */
idev->fake = g_new0(struct fake_input, 1);
idev->fake->ch = ch;
@@ -1058,6 +1109,23 @@
}
del_stored_device_info(&idev->src, &idev->dst);
+
+ devices = g_slist_remove(devices, idev);
+
+ /*
+ * Workaround: if connected, the watch will not be able
+ * to access the D-Bus data assigned to this path
+ * because the object path data was destroyed.
+ */
+ if (idev->watch) {
+ g_source_remove(idev->watch);
+ idev->watch = 0;
+ dbus_connection_emit_signal(conn,
+ path,
+ INPUT_DEVICE_INTERFACE,
+ "Disconnected",
+ DBUS_TYPE_INVALID);
+ }
dbus_connection_destroy_object_path(conn, path);
@@ -1069,32 +1137,16 @@
return 0;
}
-int input_device_get_bdaddr(DBusConnection *conn, const char *path,
- bdaddr_t *src, bdaddr_t *dst)
-{
- struct device *idev;
-
- if (!dbus_connection_get_object_user_data(conn, path,
- (void *) &idev))
- return -1;
-
- if (!idev)
- return -1;
-
- bacpy(src, &idev->src);
- bacpy(dst, &idev->dst);
-
- return 0;
-}
-
-int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm, GIOFunc cb, void *data)
+int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm,
+ GIOFunc cb, void *data)
{
GIOChannel *io;
struct sockaddr_l2 addr;
struct l2cap_options opts;
int sk, err;
- if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0)
+ sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ if (sk < 0)
return -1;
memset(&addr, 0, sizeof(addr));
@@ -1108,12 +1160,14 @@
goto failed;
memset(&opts, 0, sizeof(opts));
+#if 0
opts.imtu = HIDP_DEFAULT_MTU;
opts.omtu = HIDP_DEFAULT_MTU;
opts.flush_to = 0xffff;
if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0)
goto failed;
+#endif
memset(&addr, 0, sizeof(addr));
addr.l2_family = AF_BLUETOOTH;
@@ -1131,9 +1185,8 @@
g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
(GIOFunc) cb, data);
- } else {
+ } else
cb(io, G_IO_OUT, data);
- }
g_io_channel_unref(io);
@@ -1146,3 +1199,92 @@
return -1;
}
+
+static struct device *find_device(bdaddr_t *src, bdaddr_t *dst)
+{
+ struct device *idev;
+ GSList *list;
+
+ for (list = devices; list != NULL; list = list->next) {
+ idev = list->data;
+
+ if (!bacmp(&idev->src, src) && !bacmp(&idev->dst, dst))
+ return idev;
+ }
+
+ return NULL;
+}
+
+gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst)
+{
+ struct device *idev = find_device(src, dst);
+ if (!idev)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk)
+{
+ struct device *idev = find_device(src, dst);
+ if (!idev)
+ return -ENOENT;
+
+ switch (psm) {
+ case L2CAP_PSM_HIDP_CTRL:
+ idev->ctrl_sk = nsk;
+ break;
+ case L2CAP_PSM_HIDP_INTR:
+ idev->intr_sk = nsk;
+ break;
+ }
+
+ return 0;
+}
+
+int input_device_close_channels(bdaddr_t *src, bdaddr_t *dst)
+{
+ struct device *idev = find_device(src, dst);
+ if (!idev)
+ return -ENOENT;
+
+ if (idev->ctrl_sk >= 0) {
+ close(idev->ctrl_sk);
+ idev->ctrl_sk = -1;
+ }
+
+ if (idev->intr_sk >= 0) {
+ close(idev->intr_sk);
+ idev->intr_sk = -1;
+ }
+
+ return 0;
+}
+
+int input_device_connadd(bdaddr_t *src, bdaddr_t *dst)
+{
+ struct device *idev;
+ int err;
+
+ idev = find_device(src, dst);
+ if (!idev)
+ return -ENOENT;
+
+ err = hidp_connadd(src, dst, idev->ctrl_sk, idev->intr_sk, idev->name);
+ if (err < 0) {
+ close(idev->ctrl_sk);
+ close(idev->intr_sk);
+ idev->ctrl_sk = -1;
+ idev->intr_sk = -1;
+
+ return err;
+ }
+
+ idev->watch = create_watch(idev->ctrl_sk, idev);
+ dbus_connection_emit_signal(idev->conn,
+ idev->path,
+ INPUT_DEVICE_INTERFACE,
+ "Connected",
+ DBUS_TYPE_INVALID);
+ return 0;
+}
Modified: bluez-utils/branches/upstream/current/input/device.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/input/device.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/input/device.h (original)
+++ bluez-utils/branches/upstream/current/input/device.h Wed Jul 4 13:37:57 2007
@@ -20,16 +20,23 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
-#define L2CAP_PSM_HIDP_CTRL 0x11
-#define L2CAP_PSM_HIDP_INTR 0x13
+
+#define L2CAP_PSM_HIDP_CTRL 0x11
+#define L2CAP_PSM_HIDP_INTR 0x13
int input_device_register(DBusConnection *conn, bdaddr_t *src, bdaddr_t *dst,
- struct hidp_connadd_req *hidp, const char **ppath);
+ struct hidp_connadd_req *hidp, const char **ppath);
int fake_input_register(DBusConnection *conn, bdaddr_t *src,
bdaddr_t *dst, uint8_t ch, const char **ppath);
int input_device_unregister(DBusConnection *conn, const char *path);
-int input_device_get_bdaddr(DBusConnection *conn, const char *path,
- bdaddr_t *src, bdaddr_t *dst);
+gboolean input_device_is_registered(bdaddr_t *src, bdaddr_t *dst);
+
+int input_device_set_channel(bdaddr_t *src, bdaddr_t *dst, int psm, int nsk);
+
+int input_device_close_channels(bdaddr_t *src, bdaddr_t *dst);
+
+int input_device_connadd(bdaddr_t *src, bdaddr_t *dst);
+
int l2cap_connect(bdaddr_t *src, bdaddr_t *dst,
- unsigned short psm, GIOFunc cb, void *data);
+ unsigned short psm, GIOFunc cb, void *data);
Modified: bluez-utils/branches/upstream/current/input/manager.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/input/manager.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/input/manager.c (original)
+++ bluez-utils/branches/upstream/current/input/manager.c Wed Jul 4 13:37:57 2007
@@ -778,23 +778,12 @@
dbus_message_unref(reply);
}
-static int path_bdaddr_cmp(const char *path, const bdaddr_t *bdaddr)
-{
- bdaddr_t src, dst;
-
- if (input_device_get_bdaddr(connection, path, &src, &dst) < 0)
- return -1;
-
- return bacmp(&dst, bdaddr);
-}
-
static DBusHandlerResult create_device(DBusConnection *conn,
DBusMessage *msg, void *data)
{
struct pending_req *pr;
DBusError derr;
const char *addr;
- GSList *l;
bdaddr_t src, dst;
uint32_t cls = 0;
int dev_id;
@@ -821,10 +810,7 @@
}
str2ba(addr, &dst);
-
- l = g_slist_find_custom(device_paths, &dst,
- (GCompareFunc) path_bdaddr_cmp);
- if (l)
+ if (input_device_is_registered(&src, &dst))
return err_already_exists(conn, msg, "Input Already exists");
if (read_device_class(&src, &dst, &cls) < 0) {
@@ -954,9 +940,40 @@
* acceptable since the source is different.
*/
if (input_device_register(connection, src, &dst, &hidp, &path) < 0)
+ goto cleanup;
+
+ device_paths = g_slist_append(device_paths, g_strdup(path));
+cleanup:
+ if (hidp.rd_data)
+ g_free(hidp.rd_data);
+}
+
+/* hidd to input transition function */
+static void stored_hidd(char *key, char *value, void *data)
+{
+ struct hidp_connadd_req hidp;
+ char *str, filename[PATH_MAX + 1], addr[18];
+ bdaddr_t dst, *src = data;
+
+ ba2str(src, addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "input");
+
+ str = textfile_get(filename, key);
+ if (str) {
+ /* Skip: entry found in input file */
+ free(str);
return;
-
- device_paths = g_slist_append(device_paths, g_strdup(path));
+ }
+
+ memset(&hidp, 0, sizeof(struct hidp_connadd_req));
+
+ if (parse_stored_hidd(value, &hidp) < 0)
+ return;
+
+ str2ba(key, &dst);
+ store_device_info(src, &dst, &hidp);
+ if (hidp.rd_data)
+ g_free(hidp.rd_data);
}
static void register_stored_inputs(void)
@@ -977,10 +994,16 @@
if (!isdigit(de->d_name[0]))
continue;
+ str2ba(de->d_name, &src);
+
+ /* move the hidd entries to the input storage */
+ create_name(filename, PATH_MAX, STORAGEDIR,
+ de->d_name, "hidd");
+ textfile_foreach(filename, stored_hidd, &src);
+
+ /* load the input stored devices */
create_name(filename, PATH_MAX, STORAGEDIR,
de->d_name, "input");
-
- str2ba(de->d_name, &src);
textfile_foreach(filename, stored_input, &src);
}
Modified: bluez-utils/branches/upstream/current/input/server.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/input/server.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/input/server.c (original)
+++ bluez-utils/branches/upstream/current/input/server.c Wed Jul 4 13:37:57 2007
@@ -42,102 +42,11 @@
#include "logging.h"
#include "dbus.h"
+#include "device.h"
#include "server.h"
#include "storage.h"
-struct session_data {
- bdaddr_t src;
- bdaddr_t dst;
- int ctrl_sk;
- int intr_sk;
-};
-
-static GSList *sessions = NULL;
static DBusConnection *connection = NULL;
-
-static struct session_data *find_session(bdaddr_t *src, bdaddr_t *dst)
-{
- GSList *list;
-
- for (list = sessions; list != NULL; list = list->next) {
- struct session_data *session = list->data;
-
- if (!bacmp(&session->src, src) && !bacmp(&session->dst, dst))
- return session;
- }
-
- return NULL;
-}
-
-static gboolean session_event(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
- if (cond & G_IO_NVAL)
- return FALSE;
-
- if (cond & (G_IO_HUP | G_IO_ERR)) {
- g_io_channel_close(chan);
- return FALSE;
- }
-
- return TRUE;
-}
-
-static void create_device(struct session_data *session)
-{
- struct hidp_connadd_req req;
- char addr[18];
- int ctl, err, timeout = 30;
-
- ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
- if (ctl < 0) {
- error("Can't open HIDP interface");
- goto cleanup;
- }
-
- ba2str(&session->dst, addr);
-
- memset(&req, 0, sizeof(req));
- req.ctrl_sock = session->ctrl_sk;
- req.intr_sock = session->intr_sk;
- req.flags = 0;
- req.idle_to = timeout * 60;
-
- if (get_stored_device_info(&session->src, &session->dst, &req) < 0) {
- error("Rejected connection from unknown device %s", addr);
- goto cleanup;
- }
-
- if (req.subclass & 0x40) {
- err = encrypt_link(&session->src, &session->dst);
- if (err < 0 && err != -ENOKEY) {
- if (req.rd_data)
- free(req.rd_data);
- goto cleanup;
- }
- }
-
- info("New input device %s (%s)", addr, req.name);
-
- if (req.vendor == 0x054c && req.product == 0x0268) {
- unsigned char buf[] = { 0x53, 0xf4, 0x42, 0x03, 0x00, 0x00 };
- err = write(session->ctrl_sk, buf, sizeof(buf));
- }
-
- err = ioctl(ctl, HIDPCONNADD, &req);
-
- close(ctl);
-
- if (req.rd_data)
- free(req.rd_data);
-
-cleanup:
- sessions = g_slist_remove(sessions, session);
-
- close(session->intr_sk);
- close(session->ctrl_sk);
-
- g_free(session);
-}
static void cancel_authorization(const char *addr)
{
@@ -160,38 +69,41 @@
send_message_and_unref(connection, msg);
}
+struct authorization_data {
+ bdaddr_t src;
+ bdaddr_t dst;
+};
+
static void authorization_callback(DBusPendingCall *pcall, void *data)
{
- struct session_data *session = data;
+ struct authorization_data *auth = data;
DBusMessage *reply = dbus_pending_call_steal_reply(pcall);
DBusError derr;
dbus_error_init(&derr);
- if (dbus_set_error_from_message(&derr, reply)) {
- error("Access denied: %s", derr.message);
- if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) {
- char addr[18];
- memset(addr, 0, sizeof(addr));
- ba2str(&session->dst, addr);
- cancel_authorization(addr);
- }
- dbus_error_free(&derr);
-
- sessions = g_slist_remove(sessions, session);
-
- close(session->intr_sk);
- close(session->ctrl_sk);
-
- g_free(session);
- } else {
- create_device(session);
- }
-
+ if (dbus_set_error_from_message(&derr, reply) != TRUE) {
+ dbus_message_unref(reply);
+ input_device_connadd(&auth->src, &auth->dst);
+ return;
+ }
+
+ error("Authorization denied: %s", derr.message);
+ if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY)) {
+ char addr[18];
+ memset(addr, 0, sizeof(addr));
+ ba2str(&auth->dst, addr);
+ cancel_authorization(addr);
+ }
+
+ input_device_close_channels(&auth->src, &auth->dst);
+
+ dbus_error_free(&derr);
dbus_message_unref(reply);
}
-static int authorize_device(struct session_data *session)
-{
+static int authorize_device(bdaddr_t *src, bdaddr_t *dst)
+{
+ struct authorization_data *auth;
DBusMessage *msg;
DBusPendingCall *pending;
char addr[18];
@@ -206,7 +118,7 @@
}
memset(addr, 0, sizeof(addr));
- ba2str(&session->dst, addr);
+ ba2str(dst, addr);
dbus_message_append_args(msg,
DBUS_TYPE_STRING, &paddr,
DBUS_TYPE_STRING, &uuid,
@@ -216,28 +128,18 @@
msg, &pending, -1) == FALSE)
return -EACCES;
- dbus_pending_call_set_notify(pending, authorization_callback, session, NULL);
+ auth = g_new0(struct authorization_data, 1);
+ bacpy(&auth->src, src);
+ bacpy(&auth->dst, dst);
+ dbus_pending_call_set_notify(pending, authorization_callback, auth, g_free);
dbus_pending_call_unref(pending);
dbus_message_unref(msg);
return 0;
}
-static void create_watch(int sk, struct session_data *session)
-{
- GIOChannel *io;
-
- io = g_io_channel_unix_new(sk);
-
- g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- session_event, session);
-
- g_io_channel_unref(io);
-}
-
static gboolean connect_event(GIOChannel *chan, GIOCondition cond, gpointer data)
{
- struct session_data *session;
struct sockaddr_l2 addr;
socklen_t addrlen;
bdaddr_t src, dst;
@@ -268,43 +170,19 @@
debug("Incoming connection on PSM %d", psm);
- session = find_session(&src, &dst);
- if (session) {
- if (psm == 19) {
- session->intr_sk = nsk;
- if (authorize_device(session) < 0) {
- error("Authorization request failed");
- sessions = g_slist_remove(sessions, session);
-
- close(session->intr_sk);
- close(session->ctrl_sk);
-
- g_free(session);
-
- return TRUE;
- }
- debug("Waiting authorization ...");
- } else {
- error("Control channel already established");
- close(nsk);
+ if (input_device_set_channel(&src, &dst, psm, nsk) < 0) {
+ /* Send unplug virtual cable to unknown devices */
+ if (psm == L2CAP_PSM_HIDP_CTRL) {
+ unsigned char unplug[] = { 0x15 };
+ int err;
+ err = write(nsk, unplug, sizeof(unplug));
}
- } else {
- if (psm == 17) {
- session = g_new0(struct session_data, 1);
-
- bacpy(&session->src, &src);
- bacpy(&session->dst, &dst);
- session->ctrl_sk = nsk;
- session->intr_sk = -1;
-
- sessions = g_slist_append(sessions, session);
-
- create_watch(nsk, session);
- } else {
- error("No control channel available");
- close(nsk);
- }
- }
+ close(nsk);
+ return TRUE;
+ }
+
+ if ((psm == L2CAP_PSM_HIDP_INTR) && (authorize_device(&src, &dst) < 0))
+ input_device_close_channels(&src, &dst);
return TRUE;
}
@@ -347,14 +225,14 @@
int server_start(DBusConnection *conn)
{
- ctrl_io = setup_l2cap(17);
+ ctrl_io = setup_l2cap(L2CAP_PSM_HIDP_CTRL);
if (!ctrl_io) {
error("Failed to listen on control channel");
return -1;
}
g_io_channel_set_close_on_unref(ctrl_io, TRUE);
- intr_io = setup_l2cap(19);
+ intr_io = setup_l2cap(L2CAP_PSM_HIDP_INTR);
if (!intr_io) {
error("Failed to listen on interrupt channel");
g_io_channel_unref(ctrl_io);
Modified: bluez-utils/branches/upstream/current/input/storage.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/input/storage.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/input/storage.c (original)
+++ bluez-utils/branches/upstream/current/input/storage.c Wed Jul 4 13:37:57 2007
@@ -59,22 +59,22 @@
return create_name(buf, size, STORAGEDIR, addr, name);
}
-int parse_stored_device_info(const char *str, struct hidp_connadd_req *req)
+int parse_stored_hidd(const char *str, struct hidp_connadd_req *req)
{
char tmp[3];
- const char *desc;
+ char *desc;
unsigned int vendor, product, version, subclass, country, parser, pos;
- size_t len;
int i;
- sscanf(str, "%04X:%04X:%04X %02X %02X %04X %08X %n",
+ desc = malloc(4096);
+ if (!desc)
+ return -ENOMEM;
+
+ memset(desc, 0, 4096);
+
+ sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n",
&vendor, &product, &version, &subclass, &country,
- &parser, &req->flags, &pos);
-
- desc = &str[pos];
- len = strlen(desc);
- if (len <= 0)
- return -ENOENT;
+ &parser, desc, &req->flags, &pos);
req->vendor = vendor;
req->product = product;
@@ -83,9 +83,10 @@
req->country = country;
req->parser = parser;
- req->rd_size = len / 2;
+ req->rd_size = strlen(desc) / 2;
req->rd_data = g_try_malloc0(req->rd_size);
if (!req->rd_data) {
+ g_free(desc);
return -ENOMEM;
}
@@ -95,6 +96,47 @@
req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16);
}
+ g_free(desc);
+
+ return 0;
+}
+
+int parse_stored_device_info(const char *str, struct hidp_connadd_req *req)
+{
+ char tmp[3];
+ const char *desc;
+ unsigned int vendor, product, version, subclass, country, parser, pos;
+ size_t len;
+ int i;
+
+ sscanf(str, "%04X:%04X:%04X %02X %02X %04X %08X %n",
+ &vendor, &product, &version, &subclass, &country,
+ &parser, &req->flags, &pos);
+
+ desc = &str[pos];
+ len = strlen(desc);
+ if (len <= 0)
+ return -ENOENT;
+
+ req->vendor = vendor;
+ req->product = product;
+ req->version = version;
+ req->subclass = subclass;
+ req->country = country;
+ req->parser = parser;
+
+ req->rd_size = len / 2;
+ req->rd_data = g_try_malloc0(req->rd_size);
+ if (!req->rd_data) {
+ return -ENOMEM;
+ }
+
+ memset(tmp, 0, sizeof(tmp));
+ for (i = 0; i < req->rd_size; i++) {
+ memcpy(tmp, desc + (i * 2), 2);
+ req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16);
+ }
+
return 0;
}
@@ -124,10 +166,12 @@
char filename[PATH_MAX + 1];
char addr[18];
+ ba2str(dst, addr);
+
+ create_filename(filename, PATH_MAX, src, "hidd");
+ textfile_del(filename, addr);
+
create_filename(filename, PATH_MAX, src, "input");
-
- ba2str(dst, addr);
-
return textfile_del(filename, addr);
}
Modified: bluez-utils/branches/upstream/current/input/storage.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/input/storage.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/input/storage.h (original)
+++ bluez-utils/branches/upstream/current/input/storage.h Wed Jul 4 13:37:57 2007
@@ -29,6 +29,7 @@
int store_device_info(bdaddr_t *src, bdaddr_t *dst,
struct hidp_connadd_req *req);
+int parse_stored_hidd(const char *str, struct hidp_connadd_req *req);
int parse_stored_device_info(const char *str,
struct hidp_connadd_req *req);
Modified: bluez-utils/branches/upstream/current/network/connection.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/connection.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/connection.c (original)
+++ bluez-utils/branches/upstream/current/network/connection.c Wed Jul 4 13:37:57 2007
@@ -28,7 +28,7 @@
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
-
+#include <sys/stat.h>
#include <netinet/in.h>
#include <bluetooth/bluetooth.h>
@@ -675,7 +675,8 @@
return 0;
}
-int connection_store(DBusConnection *conn, const char *path)
+int connection_store(DBusConnection *conn, const char *path,
+ gboolean default_path)
{
struct network_conn *nc;
const char *role;
@@ -696,25 +697,29 @@
role = bnep_name(nc->id);
snprintf(key, 32, "%s#%s", dst_addr, role);
- len = strlen(nc->name) + strlen(nc->desc) + 2;
- value = g_malloc0(len);
- snprintf(value, len, "%s:%s", nc->name, nc->desc);
-
ba2str(&nc->src, src_addr);
create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "network");
-
- err = textfile_put(filename, key, value);
-
- g_free(value);
-
- return err;
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ if (default_path)
+ err = textfile_put(filename, "default", key);
+ else {
+ len = strlen(nc->name) + strlen(nc->desc) + 2;
+ value = g_malloc0(len);
+ snprintf(value, len, "%s:%s", nc->name, nc->desc);
+ err = textfile_put(filename, key, value);
+ g_free(value);
+ }
+
+ return err;
}
int connection_find_data(DBusConnection *conn,
const char *path, const char *pattern)
{
struct network_conn *nc;
- char addr[18];
+ char addr[18], key[32];
+ const char *role;
if (!dbus_connection_get_object_user_data(conn, path, (void *) &nc))
return -1;
@@ -730,6 +735,12 @@
if (strcasecmp(pattern, addr) == 0)
return 0;
+ role = bnep_name(nc->id);
+ snprintf(key, 32, "%s#%s", addr, role);
+
+ if (strcasecmp(pattern, key) == 0)
+ return 0;
+
return -1;
}
@@ -742,3 +753,37 @@
return (nc->state == CONNECTING);
}
+
+int connection_remove_stored(DBusConnection *conn, const char *path)
+{
+ struct network_conn *nc;
+ const char *role;
+ char key[32];
+ char filename[PATH_MAX + 1];
+ char src_addr[18], dst_addr[18];
+ int err;
+
+ if (!dbus_connection_get_object_user_data(conn, path, (void *) &nc))
+ return -ENOENT;
+
+ ba2str(&nc->dst, dst_addr);
+ role = bnep_name(nc->id);
+ snprintf(key, 32, "%s#%s", dst_addr, role);
+
+ ba2str(&nc->src, src_addr);
+ create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "network");
+
+ err = textfile_del(filename, key);
+
+ return err;
+}
+
+gboolean connection_is_connected(DBusConnection *conn, const char *path)
+{
+ struct network_conn *nc;
+
+ if (!dbus_connection_get_object_user_data(conn, path, (void *) &nc))
+ return FALSE;
+
+ return (nc->state == CONNECTED);
+}
Modified: bluez-utils/branches/upstream/current/network/connection.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/connection.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/connection.h (original)
+++ bluez-utils/branches/upstream/current/network/connection.h Wed Jul 4 13:37:57 2007
@@ -23,7 +23,10 @@
int connection_register(DBusConnection *conn, const char *path, bdaddr_t *src,
bdaddr_t *dst, uint16_t id, const char *name, const char *desc);
-int connection_store(DBusConnection *conn, const char *path);
+int connection_store(DBusConnection *conn, const char *path,
+ gboolean default_path);
+int connection_remove_stored(DBusConnection *conn, const char *path);
int connection_find_data(DBusConnection *conn, const char *path,
const char *pattern);
gboolean connection_has_pending(DBusConnection *conn, const char *path);
+gboolean connection_is_connected(DBusConnection *conn, const char *path);
Modified: bluez-utils/branches/upstream/current/network/manager.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/manager.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/manager.c (original)
+++ bluez-utils/branches/upstream/current/network/manager.c Wed Jul 4 13:37:57 2007
@@ -45,7 +45,6 @@
#include "logging.h"
#include "textfile.h"
-#define NETWORK_PATH "/org/bluez/network"
#define NETWORK_MANAGER_INTERFACE "org.bluez.network.Manager"
#include "error.h"
@@ -54,8 +53,6 @@
#include "server.h"
#include "connection.h"
#include "common.h"
-
-#define MAX_PATH_LENGTH 64 /* D-Bus path */
struct pending_reply {
DBusConnection *conn;
@@ -70,6 +67,7 @@
static GSList *server_paths = NULL; /* Network registered servers paths */
static GSList *connection_paths = NULL; /* Network registered connections paths */
+static int default_index = -1; /* Network default connection path index */
static DBusConnection *connection = NULL;
@@ -139,6 +137,27 @@
return send_message_and_unref(conn, reply);
}
+static const char * last_connection_used(DBusConnection *conn)
+{
+ const char *path = NULL;
+ GSList *l;
+ int i;
+
+ for (i = g_slist_length (connection_paths) -1; i > -1; i--) {
+ path = g_slist_nth_data (connection_paths, i);
+ if (connection_is_connected(conn, path))
+ break;
+ }
+
+ /* No connection connected fallback to last connection */
+ if (i == -1) {
+ l = g_slist_last(connection_paths);
+ path = l->data;
+ }
+
+ return path;
+}
+
static DBusHandlerResult remove_path(DBusConnection *conn,
DBusMessage *msg, GSList **list,
const char *sname)
@@ -161,8 +180,20 @@
if (!l)
return err_does_not_exist(conn, msg, "Path doesn't exist");
- if (*list == connection_paths && connection_has_pending (conn, path))
- return err_failed(conn, msg, "Connection is Busy");
+ /* Remove references from the storage */
+ if (*list == connection_paths) {
+ if (connection_has_pending(conn, path))
+ return err_failed(conn, msg, "Connection is Busy");
+
+ connection_remove_stored(conn, path);
+ /* Reset default connection */
+ if (l == g_slist_nth(*list, default_index)) {
+ const char *dpath;
+
+ dpath = last_connection_used(conn);
+ connection_store(conn, dpath, TRUE);
+ }
+ }
g_free(l->data);
*list = g_slist_remove(*list, l->data);
@@ -171,8 +202,6 @@
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- /* Remove the nap or gn file from the file system */
- server_remove_stored(conn, path);
if (!dbus_connection_destroy_object_path(conn, path))
error("Network path unregister failed");
@@ -246,7 +275,7 @@
goto fail;
}
- connection_store(pr->conn, pr->path);
+ connection_store(pr->conn, pr->path, FALSE);
connection_paths = g_slist_append(connection_paths, g_strdup(pr->path));
create_path(pr->conn, pr->msg, pr->path, "ConnectionCreated");
@@ -373,57 +402,6 @@
return list_paths(conn, msg, server_paths);
}
-static DBusHandlerResult create_server(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- char path[MAX_PATH_LENGTH];
- DBusError derr;
- const char *str;
- bdaddr_t src;
- uint16_t id;
- int dev_id;
-
- dbus_error_init(&derr);
- if (!dbus_message_get_args(msg, &derr,
- DBUS_TYPE_STRING, &str,
- DBUS_TYPE_INVALID)) {
- err_invalid_args(conn, msg, derr.message);
- dbus_error_free(&derr);
- return DBUS_HANDLER_RESULT_HANDLED;
- }
-
- id = bnep_service_id(str);
- if ((id != BNEP_SVC_GN) && (id != BNEP_SVC_NAP))
- return err_invalid_args(conn, msg, "Not supported");
-
- snprintf(path, MAX_PATH_LENGTH, NETWORK_PATH"/server/%s%d",
- bnep_name(id), net_uid++);
-
- if (g_slist_find_custom(server_paths, path,
- (GCompareFunc) strcmp)) {
- err_already_exists(conn, msg, "Server Already exists");
- return DBUS_HANDLER_RESULT_HANDLED;
- }
-
- bacpy(&src, BDADDR_ANY);
-
- dev_id = hci_get_route(NULL);
-
- if (dev_id >= 0)
- hci_devba(dev_id, &src);
-
- if (server_register(conn, path, &src, id) < 0)
- return err_failed(conn, msg,
- "D-Bus path registration failed");
-
- if (bacmp(&src, BDADDR_ANY) != 0)
- server_store(conn, path);
-
- server_paths = g_slist_append(server_paths, g_strdup(path));
-
- return create_path(conn, msg, path, "ServerCreated");
-}
-
static DBusHandlerResult find_server(DBusConnection *conn,
DBusMessage *msg, void *data)
{
@@ -463,16 +441,28 @@
return send_message_and_unref(conn, reply);
}
-static DBusHandlerResult remove_server(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- return remove_path(conn, msg, &server_paths, "ServerRemoved");
-}
-
static DBusHandlerResult list_connections(DBusConnection *conn,
DBusMessage *msg, void *data)
{
return list_paths(conn, msg, connection_paths);
+}
+
+static GSList * find_connection_pattern(DBusConnection *conn,
+ const char *pattern)
+{
+ const char *path;
+ GSList *list;
+
+ if (pattern == NULL)
+ return NULL;
+
+ for (list = connection_paths; list; list = list->next) {
+ path = (const char *) list->data;
+ if (connection_find_data(conn, path, pattern) == 0)
+ break;
+ }
+
+ return list;
}
static DBusHandlerResult find_connection(DBusConnection *conn,
@@ -493,16 +483,14 @@
return DBUS_HANDLER_RESULT_HANDLED;
}
- for (list = connection_paths; list; list = list->next) {
- path = (const char *) list->data;
- if (connection_find_data(conn, path, pattern) == 0)
- break;
- }
+ list = find_connection_pattern(conn, pattern);
if (list == NULL) {
err_failed(conn, msg, "No such connection");
return DBUS_HANDLER_RESULT_HANDLED;
}
+
+ path = list->data;
reply = dbus_message_new_method_return(msg);
if (!reply)
@@ -524,6 +512,8 @@
bdaddr_t src;
uint16_t id;
int dev_id;
+ char key[32];
+ GSList *l;
dbus_error_init(&derr);
if (!dbus_message_get_args(msg, &derr,
@@ -538,6 +528,17 @@
id = bnep_service_id(str);
if ((id != BNEP_SVC_GN) && (id != BNEP_SVC_NAP))
return err_invalid_args(conn, msg, "Not supported");
+
+ snprintf(key, 32, "%s#%s", addr, bnep_name(id));
+
+ /* Checks if the connection was already been made */
+ for (l = connection_paths; l; l = l->next) {
+ if (connection_find_data(conn, l->data, key) == 0) {
+ err_already_exists(conn, msg,
+ "Connection Already exists");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ }
bacpy(&src, BDADDR_ANY);
dev_id = hci_get_route(NULL);
@@ -570,6 +571,118 @@
return remove_path(conn, msg, &connection_paths, "ConnectionRemoved");
}
+static DBusHandlerResult last_connection(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *path;
+ DBusMessage *reply;
+
+ if (connection_paths == NULL ||
+ g_slist_length (connection_paths) == 0) {
+ err_does_not_exist(conn, msg, "No such connection");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ path = last_connection_used(conn);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ return send_message_and_unref(conn, reply);
+}
+
+static DBusHandlerResult default_connection(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *path;
+ DBusMessage *reply;
+
+ if (connection_paths == NULL ||
+ g_slist_length (connection_paths) == 0) {
+ err_does_not_exist(conn, msg, "No such connection");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ path = g_slist_nth_data (connection_paths, default_index);
+
+ if (path == NULL) {
+ path = last_connection_used(conn);
+ connection_store(conn, path, TRUE);
+ }
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ return send_message_and_unref(conn, reply);
+}
+
+static DBusHandlerResult change_default_connection(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ const char *path;
+ const char *pattern;
+ DBusMessage *reply;
+ DBusError derr;
+ GSList *list;
+
+ dbus_error_init(&derr);
+ if (!dbus_message_get_args(msg, &derr,
+ DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID)) {
+ err_invalid_args(conn, msg, derr.message);
+ dbus_error_free(&derr);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (connection_paths == NULL ||
+ g_slist_length (connection_paths) == 0) {
+ err_does_not_exist(conn, msg, "No such connection");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ list = g_slist_find_custom(connection_paths, pattern, (GCompareFunc) strcmp);
+
+ /* Find object path via pattern */
+ if (list == NULL) {
+ list = find_connection_pattern(conn, pattern);
+
+ if (list == NULL) {
+ err_failed(conn, msg, "No such connection");
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+ else
+ path = list->data;
+ }
+ else
+ path = list->data;
+
+ default_index = g_slist_position (connection_paths, list);
+ connection_store(connection, path, TRUE);
+
+ dbus_connection_emit_signal(connection, NETWORK_PATH,
+ NETWORK_MANAGER_INTERFACE,
+ "DefaultConnectionChanged",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ return send_message_and_unref(conn, reply);
+}
+
static void manager_unregister(DBusConnection *conn, void *data)
{
info("Unregistered manager path");
@@ -644,22 +757,117 @@
if (connection_register(connection, path, src,
&dst, id, name, ptr) == 0) {
- connection_paths = g_slist_append(connection_paths,
- g_strdup(path));
+ char *rpath = g_strdup(path);
+ connection_paths = g_slist_append(connection_paths, rpath);
+ dbus_connection_emit_signal(connection, NETWORK_PATH,
+ NETWORK_MANAGER_INTERFACE,
+ "ConnectionCreated",
+ DBUS_TYPE_STRING, &rpath,
+ DBUS_TYPE_INVALID);
}
g_free(name);
}
-static void register_stored(void)
-{
- char dirname[PATH_MAX + 1];
+static void register_connections_stored(const char *adapter)
+{
+ char filename[PATH_MAX + 1];
+ char *pattern;
+ struct stat s;
+ GSList *list;
+ bdaddr_t src;
+ bdaddr_t default_src;
+ int dev_id;
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter, "network");
+
+ str2ba(adapter, &src);
+
+ bacpy(&default_src, BDADDR_ANY);
+ dev_id = hci_get_route(NULL);
+ if (dev_id < 0)
+ hci_devba(dev_id, &default_src);
+
+ if (stat (filename, &s) == 0 && (s.st_mode & __S_IFREG)) {
+ textfile_foreach(filename, parse_stored_connection, &src);
+ pattern = textfile_get(filename, "default");
+
+ list = find_connection_pattern(connection, pattern);
+ if (list != NULL)
+ default_index = g_slist_position(connection_paths, list);
+ else if (bacmp(&src, &default_src) == 0) {
+ list = g_slist_last(connection_paths);
+ if (list == NULL)
+ return;
+ default_index = g_slist_position(connection_paths, list);
+ connection_store(connection, list->data, TRUE);
+ }
+ }
+}
+
+static void register_server(uint16_t id)
+{
+ char path[MAX_PATH_LENGTH];
+ bdaddr_t src;
+ int dev_id;
+
+ snprintf(path, MAX_PATH_LENGTH, NETWORK_PATH"/%s", bnep_name(id));
+
+ if (g_slist_find_custom(server_paths, path,
+ (GCompareFunc) strcmp))
+ return;
+
+ bacpy(&src, BDADDR_ANY);
+
+ dev_id = hci_get_route(NULL);
+
+ if (dev_id >= 0)
+ hci_devba(dev_id, &src);
+
+ if (server_register(connection, path, &src, id) < 0)
+ return;
+
+ if (bacmp(&src, BDADDR_ANY) != 0)
+ server_store(connection, path);
+
+ server_paths = g_slist_append(server_paths, g_strdup(path));
+}
+
+static void register_servers_stored(const char *adapter, const char *profile)
+{
char filename[PATH_MAX + 1];
char path[MAX_PATH_LENGTH];
+ uint16_t id;
+ struct stat s;
+ bdaddr_t src;
+
+ if (strcmp(profile, "nap") == 0)
+ id = BNEP_SVC_NAP;
+ else if (strcmp(profile, "gn") == 0)
+ id = BNEP_SVC_GN;
+ else
+ id = BNEP_SVC_PANU;
+
+ create_name(filename, PATH_MAX, STORAGEDIR, adapter, profile);
+
+ str2ba(adapter, &src);
+
+ if (stat (filename, &s) == 0 && (s.st_mode & __S_IFREG)) {
+ snprintf(path, MAX_PATH_LENGTH,
+ NETWORK_PATH"/%s", profile);
+ if (server_register_from_file(connection, path,
+ &src, id, filename) == 0) {
+ server_paths = g_slist_append(server_paths,
+ g_strdup(path));
+ }
+ }
+}
+
+static void register_stored(void)
+{
+ char dirname[PATH_MAX + 1];
struct dirent *de;
DIR *dir;
- struct stat s;
- bdaddr_t src;
snprintf(dirname, PATH_MAX, "%s", STORAGEDIR);
@@ -672,38 +880,16 @@
continue;
/* Connection objects */
- create_name(filename, PATH_MAX, STORAGEDIR,
- de->d_name, "network");
-
- str2ba(de->d_name, &src);
-
-
- if (stat (filename, &s) == 0 && (s.st_mode & __S_IFREG))
- textfile_foreach(filename, parse_stored_connection, &src);
+ register_connections_stored(de->d_name);
/* NAP objects */
- create_name(filename, PATH_MAX, STORAGEDIR, de->d_name, "nap");
- if (stat (filename, &s) == 0 && (s.st_mode & __S_IFREG)) {
- snprintf(path, MAX_PATH_LENGTH,
- NETWORK_PATH"/server/nap%d", net_uid++);
-
- if (server_register_from_file(connection, path,
- &src, BNEP_SVC_NAP, filename) == 0)
- server_paths = g_slist_append(server_paths,
- g_strdup(path));
- }
+ register_servers_stored(de->d_name, "nap");
/* GN objects */
- create_name(filename, PATH_MAX, STORAGEDIR, de->d_name, "gn");
- if (stat (filename, &s) == 0 && (s.st_mode & __S_IFREG)) {
- snprintf(path, MAX_PATH_LENGTH,
- NETWORK_PATH"/server/gn%d", net_uid++);
-
- if (server_register_from_file(connection, path,
- &src, BNEP_SVC_GN, filename) == 0)
- server_paths = g_slist_append(server_paths,
- g_strdup(path));
- }
+ register_servers_stored(de->d_name, "gn");
+
+ /* PANU objects */
+ register_servers_stored(de->d_name, "panu");
}
closedir(dir);
@@ -711,13 +897,14 @@
static DBusMethodVTable manager_methods[] = {
{ "ListServers", list_servers, "", "as" },
- { "CreateServer", create_server, "s", "s" },
{ "FindServer", find_server, "s", "s" },
- { "RemoveServer", remove_server, "s", "" },
{ "ListConnections", list_connections, "", "as" },
{ "FindConnection", find_connection, "s", "s" },
{ "CreateConnection", create_connection, "ss", "s" },
{ "RemoveConnection", remove_connection, "s", "" },
+ { "LastConnection", last_connection, "", "s" },
+ { "DefaultConnection", default_connection, "", "s" },
+ { "ChangeDefaultConnection", change_default_connection, "s", "s"},
{ NULL, NULL, NULL, NULL }
};
@@ -726,6 +913,7 @@
{ "ServerRemoved", "s" },
{ "ConnectionCreated", "s" },
{ "ConnectionRemoved", "s" },
+ { "DefaultConnectionChanged", "s" },
{ NULL, NULL }
};
@@ -766,6 +954,15 @@
register_stored();
+ /* PAN user server */
+ register_server(BNEP_SVC_PANU);
+
+ /* Group Network server */
+ register_server(BNEP_SVC_GN);
+
+ /* Network Access Point server */
+ register_server(BNEP_SVC_NAP);
+
return 0;
}
Modified: bluez-utils/branches/upstream/current/network/manager.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/manager.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/manager.h (original)
+++ bluez-utils/branches/upstream/current/network/manager.h Wed Jul 4 13:37:57 2007
@@ -21,6 +21,9 @@
*
*/
+#define MAX_PATH_LENGTH 64 /* D-Bus path */
+#define NETWORK_PATH "/org/bluez/network"
+
int network_init(DBusConnection *conn);
void network_exit(void);
Modified: bluez-utils/branches/upstream/current/network/network-api.txt
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/network-api.txt?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/network-api.txt (original)
+++ bluez-utils/branches/upstream/current/network/network-api.txt Wed Jul 4 13:37:57 2007
@@ -20,6 +20,7 @@
org.bluez.network.Error.Failed
void RemoveServer(string path)
+
Removes the network server object for given path.
Possible errors: org.bluez.network.Error.DoesNotExist
@@ -50,8 +51,8 @@
Removes a network connection object for a given path.
- Possible errors:org.bluez.network.Error.DoesNotExist
- org.bluez.network.Error.Failed
+ Possible errors: org.bluez.network.Error.DoesNotExist
+ org.bluez.network.Error.Failed
array{string} ListConnections()
@@ -61,18 +62,37 @@
Returns connection path.
- Possible errors:org.bluez.network.Error.DoesNotExist
- org.bluez.network.Error.Failed
-
-Signals
-
- void ServerCreated(string path)
+ Possible errors: org.bluez.network.Error.DoesNotExist
+ org.bluez.network.Error.Failed
+
+ string LastConnection()
+
+ Returns last connected connection path, if none is connected
+ fallback to last created connection.
+
+ Possible errors: org.bluez.network.Error.DoesNotExist
+
+ string DefaultConnection()
+
+ Returns default connection path.
+
+ Possible errors: org.bluez.network.Error.DoesNotExist
+
+ string ChangeDefaultConnection(string pattern)
+
+ Changes default connection path.
+
+ Possible errors: org.bluez.network.Error.DoesNotExist
+
+Signals void ServerCreated(string path)
void ServerRemoved(string path)
void ConnectionCreated(string path)
void ConnectionRemoved(string path)
+
+ void DefaultConnectionChanged(string path)
Network Server hierarchy (experimental)
@@ -127,7 +147,6 @@
Returns the server properties.
-
Signals void Enabled()
void Disabled()
@@ -178,11 +197,13 @@
Possible errors: org.bluez.network.Error.ConnectionAttemptFailed
org.bluez.network.Error.Failed
- string CancelConnect()
+ void CancelConnect()
Abort connection attempt in case of errors or
timeouts in the client.
+ Possible errors: org.bluez.network.Error.Failed
+
void Disconnect()
Disconnects to host.
Modified: bluez-utils/branches/upstream/current/network/server.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/server.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/server.c (original)
+++ bluez-utils/branches/upstream/current/network/server.c Wed Jul 4 13:37:57 2007
@@ -59,11 +59,13 @@
#include "manager.h"
#include "server.h"
+static GIOChannel *bnep_io;
+
/* Pending Authorization */
struct pending_auth {
- char *addr; /* Bluetooth Address */
- GIOChannel *io; /* BNEP connection setup io channel */
- int attempts; /* BNEP setup conn requests counter */
+ char *addr; /* Bluetooth Address */
+ GIOChannel *io; /* BNEP connection setup io channel */
+ int attempts; /* BNEP setup conn requests counter */
};
/* Main server structure */
@@ -72,12 +74,12 @@
char *iface; /* Routing interface */
char *name; /* Server service name */
char *range; /* IP Address range */
- char *path; /* D-Bus path */
- dbus_bool_t secure;
+ char *path; /* D-Bus path */
+ gboolean enable; /* Enable flag*/
+ gboolean secure; /* Security flag*/
uint32_t record_id; /* Service record id */
uint16_t id; /* Service class identifier */
- GIOChannel *io; /* GIOChannel when listening */
- DBusConnection *conn; /* D-Bus connection */
+ DBusConnection *conn; /* D-Bus connection */
struct pending_auth *pauth; /* Pending incomming connection/authorization */
};
@@ -92,8 +94,10 @@
ba2str(src, addr);
if (id == BNEP_SVC_NAP)
create_name(filename, PATH_MAX, STORAGEDIR, addr, "nap");
- else
+ else if (id == BNEP_SVC_GN)
create_name(filename, PATH_MAX, STORAGEDIR, addr, "gn");
+ else if (id == BNEP_SVC_PANU)
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "panu");
return textfile_put(filename, key, value);
}
@@ -380,7 +384,9 @@
static gboolean connect_setup_event(GIOChannel *chan,
GIOCondition cond, gpointer data)
{
- struct network_server *ns = data;
+ DBusConnection *conn = data;
+ struct network_server *ns;
+ char path[MAX_PATH_LENGTH];
struct bnep_setup_conn_req *req;
unsigned char pkt[BNEP_MTU];
gsize n;
@@ -437,7 +443,10 @@
/* Getting source service: considering 2 bytes size */
role = ntohs(bt_get_unaligned((uint16_t *) pservice));
- if (role != BNEP_SVC_PANU) {
+ snprintf(path, MAX_PATH_LENGTH, NETWORK_PATH"/%s", bnep_name(role));
+ dbus_connection_get_object_user_data(conn, path, (void *) &ns);
+
+ if (ns == NULL || ns->enable == FALSE) {
response = BNEP_CONN_INVALID_SRC;
goto reply;
}
@@ -532,7 +541,7 @@
return TRUE;
}
-static int l2cap_listen(struct network_server *ns)
+int server_init(DBusConnection *conn, gboolean secure)
{
struct l2cap_options l2o;
struct sockaddr_l2 l2a;
@@ -578,7 +587,7 @@
}
/* Set link mode */
- lm = (ns->secure ? L2CAP_LM_SECURE : 0);
+ lm = (secure ? L2CAP_LM_SECURE : 0);
if (lm && setsockopt(sk, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm)) < 0) {
err = errno;
error("Failed to set link mode. %s(%d)",
@@ -592,11 +601,11 @@
goto fail;
}
- ns->io = g_io_channel_unix_new(sk);
- g_io_channel_set_close_on_unref(ns->io, FALSE);
-
- g_io_add_watch(ns->io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- connect_event, ns);
+ bnep_io = g_io_channel_unix_new(sk);
+ g_io_channel_set_close_on_unref(bnep_io, FALSE);
+
+ g_io_add_watch(bnep_io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+ connect_event, conn);
return 0;
fail:
@@ -762,8 +771,7 @@
return -EIO;
}
- err = l2cap_listen(ns);
- if (err < 0)
+ if (bnep_io == NULL && (err = server_init(ns->conn, ns->secure)) < 0)
return -err;
return 0;
@@ -776,7 +784,7 @@
DBusMessage *reply;
int err;
- if (ns->io)
+ if (ns->enable)
return err_already_exists(conn, msg, "Server already enabled");
if (bacmp(&ns->src, BDADDR_ANY) == 0) {
@@ -816,7 +824,7 @@
if (!reply)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
- if (!ns->io)
+ if (!ns->enable)
return err_failed(conn, msg, "Not enabled");
/* Remove the service record */
@@ -825,9 +833,7 @@
ns->record_id = 0;
}
- g_io_channel_close(ns->io);
- g_io_channel_unref(ns->io);
- ns->io = NULL;
+ ns->enable = FALSE;
store_property(&ns->src, ns->id, "enabled", "0");
@@ -865,13 +871,15 @@
g_free(ns->name);
ns->name = g_strdup(name);
- if (ns->io) {
+ if (ns->enable) {
if (update_server_record(ns) < 0) {
dbus_message_unref(reply);
return err_failed(conn, msg,
"Service record attribute update failed");
}
}
+
+ store_property(&ns->src, ns->id, "name", ns->name);
return send_message_and_unref(conn, reply);
}
@@ -955,7 +963,7 @@
}
ns->secure = secure;
- if (ns->io) {
+ if (ns->enable) {
if (update_server_record(ns) < 0) {
dbus_message_unref(reply);
return err_failed(conn, msg,
@@ -963,6 +971,8 @@
}
}
+ store_property(&ns->src, ns->id, "secure", "1");
+
return send_message_and_unref(conn, reply);
}
@@ -1039,11 +1049,6 @@
if (ns->conn)
dbus_connection_unref(ns->conn);
- if (ns->io) {
- g_io_channel_close(ns->io);
- g_io_channel_unref(ns->io);
- }
-
g_free(ns);
}
@@ -1054,6 +1059,12 @@
info("Unregistered server path:%s", ns->path);
server_free(ns);
+
+ if (bnep_io != NULL) {
+ g_io_channel_close(bnep_io);
+ g_io_channel_unref(bnep_io);
+ bnep_io = NULL;
+ }
}
static DBusMethodVTable server_methods[] = {
@@ -1081,10 +1092,7 @@
{
struct network_server *ns;
- if (!conn)
- return -EINVAL;
-
- if (!path)
+ if (!conn || !path)
return -EINVAL;
ns = g_new0(struct network_server, 1);
@@ -1109,8 +1117,10 @@
/* Setting a default name */
if (id == BNEP_SVC_NAP)
ns->name = g_strdup("BlueZ NAP service");
+ else if (id == BNEP_SVC_GN)
+ ns->name = g_strdup("BlueZ GN service");
else
- ns->name = g_strdup("BlueZ GN service");
+ ns->name = g_strdup("BlueZ PANU service");
ns->path = g_strdup(path);
ns->id = id;
@@ -1193,8 +1203,10 @@
ba2str(&ns->src, addr);
if (ns->id == BNEP_SVC_NAP)
create_name(filename, PATH_MAX, STORAGEDIR, addr, "nap");
+ else if (ns->id == BNEP_SVC_GN)
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "gn");
else
- create_name(filename, PATH_MAX, STORAGEDIR, addr, "gn");
+ create_name(filename, PATH_MAX, STORAGEDIR, addr, "panu");
create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
@@ -1208,25 +1220,9 @@
textfile_put(filename, "secure", ns->secure ? "1": "0");
+ textfile_put(filename, "enabled", ns->enable ? "1": "0");
+
return 0;
-}
-
-int server_remove_stored(DBusConnection *conn, const char *path)
-{
- struct network_server *ns;
- char filename[PATH_MAX + 1];
- char addr[18];
-
- if (!dbus_connection_get_object_user_data(conn, path, (void *) &ns))
- return -ENOENT;
-
- ba2str(&ns->src, addr);
- if (ns->id == BNEP_SVC_NAP)
- create_name(filename, PATH_MAX, STORAGEDIR, addr, "nap");
- else
- create_name(filename, PATH_MAX, STORAGEDIR, addr, "gn");
-
- return remove(filename);
}
int server_find_data(DBusConnection *conn,
Modified: bluez-utils/branches/upstream/current/network/server.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/server.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/server.h (original)
+++ bluez-utils/branches/upstream/current/network/server.h Wed Jul 4 13:37:57 2007
@@ -21,12 +21,13 @@
*
*/
+
int server_register(DBusConnection *conn, const char *path,
bdaddr_t *src, uint16_t id);
int server_register_from_file(DBusConnection *conn, const char *path,
const bdaddr_t *src, uint16_t id, const char *filename);
int server_store(DBusConnection *conn, const char *path);
-int server_remove_stored(DBusConnection *conn, const char *path);
+
int server_find_data(DBusConnection *conn, const char *path,
const char *pattern);
Modified: bluez-utils/branches/upstream/current/network/test-network
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/network/test-network?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/network/test-network (original)
+++ bluez-utils/branches/upstream/current/network/test-network Wed Jul 4 13:37:57 2007
@@ -23,3 +23,9 @@
'org.bluez.network.Server')
except:
pass
+
+try:
+ panu = dbus.Interface(bus.get_object(conn, network.LastConnection()),
+ 'org.bluez.network.Connection')
+except:
+ pass
Modified: bluez-utils/branches/upstream/current/rfcomm/main.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/rfcomm/main.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/rfcomm/main.c (original)
+++ bluez-utils/branches/upstream/current/rfcomm/main.c Wed Jul 4 13:37:57 2007
@@ -59,6 +59,7 @@
static int encryption = 0;
static int secure = 0;
static int master = 0;
+static int linger = 0;
static char *rfcomm_state[] = {
"unknown",
@@ -100,7 +101,7 @@
if (flags & (1 << RFCOMM_TTY_ATTACHED))
strcat(str, "tty-attached");
-
+
strcat(str, "]");
return str;
}
@@ -170,7 +171,6 @@
fprintf(stderr, "Can't find a config entry for rfcomm%d\n", dev);
return -EFAULT;
}
-
} else {
str2ba(argv[1], &req.dst);
@@ -265,7 +265,7 @@
int i;
pid_t pid;
char **cmdargv;
-
+
cmdargv = malloc((argc + 1) * sizeof(char*));
if (!cmdargv)
return;
@@ -357,13 +357,22 @@
return;
}
- if (bind(sk, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
+ if (linger) {
+ struct linger l = { .l_onoff = 1, .l_linger = linger };
+
+ if (setsockopt(sk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) {
+ perror("Can't set linger option");
+ return;
+ }
+ }
+
+ if (bind(sk, (struct sockaddr *) &laddr, sizeof(laddr)) < 0) {
perror("Can't bind RFCOMM socket");
close(sk);
return;
}
- if (connect(sk, (struct sockaddr *)&raddr, sizeof(raddr)) < 0) {
+ if (connect(sk, (struct sockaddr *) &raddr, sizeof(raddr)) < 0) {
perror("Can't connect RFCOMM socket");
close(sk);
return;
@@ -393,6 +402,11 @@
snprintf(devname, MAXPATHLEN - 1, "/dev/rfcomm%d", dev);
while ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
+ if (errno == EACCES) {
+ perror("Can't open RFCOMM device");
+ goto release;
+ }
+
snprintf(devname, MAXPATHLEN - 1, "/dev/bluetooth/rfcomm/%d", dev);
if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
if (try--) {
@@ -401,14 +415,7 @@
continue;
}
perror("Can't open RFCOMM device");
-
- memset(&req, 0, sizeof(req));
- req.dev_id = dev;
- req.flags = (1 << RFCOMM_HANGUP_NOW);
- ioctl(ctl, RFCOMMRELEASEDEV, &req);
-
- close(sk);
- return;
+ goto release;
}
}
@@ -457,6 +464,15 @@
printf("Disconnected\n");
close(fd);
+ return;
+
+release:
+ memset(&req, 0, sizeof(req));
+ req.dev_id = dev;
+ req.flags = (1 << RFCOMM_HANGUP_NOW);
+ ioctl(ctl, RFCOMMRELEASEDEV, &req);
+
+ close(sk);
}
static void cmd_listen(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
@@ -517,6 +533,16 @@
return;
}
+ if (linger) {
+ struct linger l = { .l_onoff = 1, .l_linger = linger };
+
+ if (setsockopt(nsk, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0) {
+ perror("Can't set linger option");
+ close(nsk);
+ return;
+ }
+ }
+
memset(&req, 0, sizeof(req));
req.dev_id = dev;
req.flags = (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP);
@@ -534,6 +560,11 @@
snprintf(devname, MAXPATHLEN - 1, "/dev/rfcomm%d", dev);
while ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
+ if (errno == EACCES) {
+ perror("Can't open RFCOMM device");
+ goto release;
+ }
+
snprintf(devname, MAXPATHLEN - 1, "/dev/bluetooth/rfcomm/%d", dev);
if ((fd = open(devname, O_RDONLY | O_NOCTTY)) < 0) {
if (try--) {
@@ -542,14 +573,7 @@
continue;
}
perror("Can't open RFCOMM device");
-
- memset(&req, 0, sizeof(req));
- req.dev_id = dev;
- req.flags = (1 << RFCOMM_HANGUP_NOW);
- ioctl(ctl, RFCOMMRELEASEDEV, &req);
-
- close(sk);
- return;
+ goto release;
}
}
@@ -606,6 +630,15 @@
printf("Disconnected\n");
close(fd);
+ return;
+
+release:
+ memset(&req, 0, sizeof(req));
+ req.dev_id = dev;
+ req.flags = (1 << RFCOMM_HANGUP_NOW);
+ ioctl(ctl, RFCOMMRELEASEDEV, &req);
+
+ close(sk);
}
static void cmd_watch(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
@@ -694,7 +727,6 @@
printf("\n");
}
-
static struct option main_options[] = {
{ "help", 0, 0, 'h' },
{ "device", 1, 0, 'i' },
@@ -704,6 +736,7 @@
{ "encrypt", 0, 0, 'E' },
{ "secure", 0, 0, 'S' },
{ "master", 0, 0, 'M' },
+ { "linger", 1, 0, 'L' },
{ 0, 0, 0, 0 }
};
@@ -714,7 +747,7 @@
bacpy(&bdaddr, BDADDR_ANY);
- while ((opt = getopt_long(argc, argv, "+i:f:rahAESM", main_options, NULL)) != -1) {
+ while ((opt = getopt_long(argc, argv, "+i:f:rahAESML:", main_options, NULL)) != -1) {
switch(opt) {
case 'i':
if (strncmp(optarg, "hci", 3) == 0)
@@ -726,6 +759,7 @@
case 'f':
rfcomm_config_file = strdup(optarg);
break;
+
case 'r':
rfcomm_raw_tty = 1;
break;
@@ -752,6 +786,10 @@
case 'M':
master = 1;
+ break;
+
+ case 'L':
+ linger = atoi(optarg);
break;
default:
Modified: bluez-utils/branches/upstream/current/rfcomm/rfcomm.1
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/rfcomm/rfcomm.1?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/rfcomm/rfcomm.1 (original)
+++ bluez-utils/branches/upstream/current/rfcomm/rfcomm.1 Wed Jul 4 13:37:57 2007
@@ -48,7 +48,7 @@
.BI -r
Switch TTY into raw mode (doesn't work with "bind").
.TP
-.BI -f " [file]"
+.BI -f " <file>"
Specify alternate config file.
.TP
.BI -i " <hciX> | <bdaddr>"
@@ -78,6 +78,9 @@
.TP
.BI -M
Become the master of a piconet
+.TP
+.BI -L " <seconds>"
+Set linger timeout
.SH COMMANDS
.TP
.BI show " <dev>"
Modified: bluez-utils/branches/upstream/current/sdpd/main.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/sdpd/main.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/sdpd/main.c (original)
+++ bluez-utils/branches/upstream/current/sdpd/main.c Wed Jul 4 13:37:57 2007
@@ -68,7 +68,6 @@
{ "help", 0, 0, 'h' },
{ "nodaemon", 0, 0, 'n' },
{ "mtu", 1, 0, 'm' },
- { "public", 0, 0, 'p' },
{ "master", 0, 0, 'M' },
{ 0, 0, 0, 0}
};
@@ -80,7 +79,7 @@
uint32_t flags = SDP_SERVER_COMPAT;
int opt, daemonize = 1, debug = 0;
- while ((opt = getopt_long(argc, argv, "ndm:pM", main_options, NULL)) != -1) {
+ while ((opt = getopt_long(argc, argv, "ndm:M", main_options, NULL)) != -1) {
switch (opt) {
case 'n':
daemonize = 0;
@@ -92,10 +91,6 @@
case 'm':
mtu = atoi(optarg);
- break;
-
- case 'p':
- flags |= SDP_SERVER_PUBLIC;
break;
case 'M':
Modified: bluez-utils/branches/upstream/current/sdpd/sdpd.8
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/sdpd/sdpd.8?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/sdpd/sdpd.8 (original)
+++ bluez-utils/branches/upstream/current/sdpd/sdpd.8 Wed Jul 4 13:37:57 2007
@@ -1,4 +1,4 @@
-.\" $Header: /cvsroot/bluez/utils/sdpd/sdpd.8,v 1.3 2007/01/24 06:11:43 holtmann Exp $
+.\" $Header: /cvsroot/bluez/utils/sdpd/sdpd.8,v 1.4 2007/05/22 11:43:30 holtmann Exp $
.\"
.\" transcript compatibility for postscript use.
.\"
@@ -70,8 +70,6 @@
Enable debugging output.
.IP "\fB-m <mtu>\fP" 10
Set maximum MTU to use on the L2CAP channel.
-.IP "\fB-p\fP" 10
-Register server record in public browse group.
.SH "BUGS"
.PP
Modified: bluez-utils/branches/upstream/current/sdpd/sdpd.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/sdpd/sdpd.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/sdpd/sdpd.h (original)
+++ bluez-utils/branches/upstream/current/sdpd/sdpd.h Wed Jul 4 13:37:57 2007
@@ -44,8 +44,8 @@
int service_update_req(sdp_req_t *req, sdp_buf_t *rsp);
int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp);
-void register_public_browse_group(int public);
-void register_server_service(int public);
+void register_public_browse_group(void);
+void register_server_service(void);
void register_device_id(const uint16_t vendor, const uint16_t product,
const uint16_t version);
@@ -80,7 +80,6 @@
#define SDP_SERVER_COMPAT (1 << 0)
#define SDP_SERVER_MASTER (1 << 1)
-#define SDP_SERVER_PUBLIC (1 << 2)
int start_sdp_server(uint16_t mtu, const char *did, uint32_t flags);
void stop_sdp_server(void);
Modified: bluez-utils/branches/upstream/current/sdpd/server.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/sdpd/server.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/sdpd/server.c (original)
+++ bluez-utils/branches/upstream/current/sdpd/server.c Wed Jul 4 13:37:57 2007
@@ -57,7 +57,7 @@
* l2cap and unix sockets over which discovery and registration clients
* access us respectively
*/
-static int init_server(uint16_t mtu, int master, int public, int compat)
+static int init_server(uint16_t mtu, int master, int compat)
{
struct l2cap_options opts;
struct sockaddr_l2 l2addr;
@@ -65,10 +65,10 @@
socklen_t optlen;
/* Register the public browse group root */
- register_public_browse_group(public);
+ register_public_browse_group();
/* Register the SDP server's service record */
- register_server_service(public);
+ register_server_service();
/* Create L2CAP socket */
l2cap_sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
@@ -104,6 +104,7 @@
return -1;
}
+ opts.omtu = mtu;
opts.imtu = mtu;
if (setsockopt(l2cap_sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
@@ -220,11 +221,10 @@
{
int compat = flags & SDP_SERVER_COMPAT;
int master = flags & SDP_SERVER_MASTER;
- int public = flags & SDP_SERVER_PUBLIC;
info("Starting SDP server");
- if (init_server(mtu, master, public, compat) < 0) {
+ if (init_server(mtu, master, compat) < 0) {
error("Server initialization failed");
return -1;
}
Modified: bluez-utils/branches/upstream/current/sdpd/service.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/sdpd/service.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/sdpd/service.c (original)
+++ bluez-utils/branches/upstream/current/sdpd/service.c Wed Jul 4 13:37:57 2007
@@ -69,51 +69,27 @@
sdp_attr_replace(server, SDP_ATTR_SVCDB_STATE, d);
}
-static void add_lang_attr(sdp_record_t *r)
-{
- sdp_lang_attr_t base_lang;
- sdp_list_t *langs = 0;
-
- base_lang.code_ISO639 = (0x65 << 8) | 0x6e;
- // UTF-8 MIBenum (http://www.iana.org/assignments/character-sets)
- base_lang.encoding = 106;
- base_lang.base_offset = SDP_PRIMARY_LANG_BASE;
- langs = sdp_list_append(0, &base_lang);
- sdp_set_lang_attr(r, langs);
- sdp_list_free(langs, 0);
-}
-
-void register_public_browse_group(int public)
+void register_public_browse_group(void)
{
sdp_list_t *browselist;
uuid_t bgscid, pbgid;
sdp_data_t *sdpdata;
sdp_record_t *browse = sdp_record_alloc();
- if (public) {
- browse->handle = sdp_next_handle();
- if (browse->handle < 0x10000)
- return;
- } else
- browse->handle = SDP_SERVER_RECORD_HANDLE + 1;
+ browse->handle = SDP_SERVER_RECORD_HANDLE + 1;
sdp_record_add(BDADDR_ANY, browse);
sdpdata = sdp_data_alloc(SDP_UINT32, &browse->handle);
sdp_attr_add(browse, SDP_ATTR_RECORD_HANDLE, sdpdata);
-
- add_lang_attr(browse);
- sdp_set_info_attr(browse, "Public Browse Group Root", "BlueZ",
- "Root of public browse hierarchy");
sdp_uuid16_create(&bgscid, BROWSE_GRP_DESC_SVCLASS_ID);
browselist = sdp_list_append(0, &bgscid);
sdp_set_service_classes(browse, browselist);
sdp_list_free(browselist, 0);
- if (public) {
- sdp_uuid16_create(&pbgid, PUBLIC_BROWSE_GROUP);
- sdp_set_group_id(browse, pbgid);
- }
+ sdp_uuid16_create(&pbgid, PUBLIC_BROWSE_GROUP);
+ sdp_attr_add_new(browse, SDP_ATTR_GROUP_ID,
+ SDP_UUID16, &pbgid.value.uuid16);
}
/*
@@ -122,17 +98,14 @@
* discovery clients. This method constructs a service record
* and stores it in the repository
*/
-void register_server_service(int public)
-{
- int i;
- sdp_list_t *classIDList, *browseList;
- sdp_list_t *access_proto = 0;
- uuid_t l2cap, classID, browseGroupId, sdpSrvUUID;
+void register_server_service(void)
+{
+ sdp_list_t *classIDList;
+ uuid_t classID;
void **versions, **versionDTDs;
uint8_t dtd;
- uint16_t version, port;
- sdp_data_t *pData, *port_data, *version_data;
- sdp_list_t *pd, *seq;
+ sdp_data_t *pData;
+ int i;
server = sdp_record_alloc();
server->pattern = NULL;
@@ -143,13 +116,6 @@
sdp_record_add(BDADDR_ANY, server);
sdp_attr_add(server, SDP_ATTR_RECORD_HANDLE,
sdp_data_alloc(SDP_UINT32, &server->handle));
-
- /*
- * Add all attributes to service record. (No need to commit since we
- * are the server and this record is already in the database.)
- */
- add_lang_attr(server);
- sdp_set_info_attr(server, "SDP Server", "BlueZ", "Bluetooth service discovery server");
sdp_uuid16_create(&classID, SDP_SERVER_SVCLASS_ID);
classIDList = sdp_list_append(0, &classID);
@@ -179,33 +145,6 @@
free(versionDTDs);
sdp_attr_add(server, SDP_ATTR_VERSION_NUM_LIST, pData);
- sdp_uuid16_create(&sdpSrvUUID, SDP_UUID);
- sdp_set_service_id(server, sdpSrvUUID);
-
- sdp_uuid16_create(&l2cap, L2CAP_UUID);
- pd = sdp_list_append(0, &l2cap);
- port = SDP_PSM;
- port_data = sdp_data_alloc(SDP_UINT16, &port);
- pd = sdp_list_append(pd, port_data);
- version = 1;
- version_data = sdp_data_alloc(SDP_UINT16, &version);
- pd = sdp_list_append(pd, version_data);
- seq = sdp_list_append(0, pd);
-
- access_proto = sdp_list_append(0, seq);
- sdp_set_access_protos(server, access_proto);
- sdp_list_free(access_proto, free);
- sdp_data_free(port_data);
- sdp_data_free(version_data);
- sdp_list_free(pd, 0);
-
- if (public) {
- sdp_uuid16_create(&browseGroupId, PUBLIC_BROWSE_GROUP);
- browseList = sdp_list_append(0, &browseGroupId);
- sdp_set_browse_groups(server, browseList);
- sdp_list_free(browseList, 0);
- }
-
update_db_timestamp();
}
Modified: bluez-utils/branches/upstream/current/serial/Makefile.am
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/Makefile.am?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/serial/Makefile.am (original)
+++ bluez-utils/branches/upstream/current/serial/Makefile.am Wed Jul 4 13:37:57 2007
@@ -10,7 +10,9 @@
service_PROGRAMS = bluetoothd-service-serial
-bluetoothd_service_serial_SOURCES = main.c manager.h manager.c
+bluetoothd_service_serial_SOURCES = main.c \
+ manager.h manager.c port.h port.c \
+ error.h error.c storage.h storage.c
LDADD = $(top_builddir)/common/libhelper.a \
@GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
Modified: bluez-utils/branches/upstream/current/serial/Makefile.in
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/Makefile.in?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/serial/Makefile.in (original)
+++ bluez-utils/branches/upstream/current/serial/Makefile.in Wed Jul 4 13:37:57 2007
@@ -53,9 +53,11 @@
servicePROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(service_PROGRAMS)
am__bluetoothd_service_serial_SOURCES_DIST = main.c manager.h \
- manager.c
+ manager.c port.h port.c error.h error.c storage.h storage.c
@SERIALSERVICE_TRUE at am_bluetoothd_service_serial_OBJECTS = \
- at SERIALSERVICE_TRUE@ main.$(OBJEXT) manager.$(OBJEXT)
+ at SERIALSERVICE_TRUE@ main.$(OBJEXT) manager.$(OBJEXT) \
+ at SERIALSERVICE_TRUE@ port.$(OBJEXT) error.$(OBJEXT) \
+ at SERIALSERVICE_TRUE@ storage.$(OBJEXT)
bluetoothd_service_serial_OBJECTS = \
$(am_bluetoothd_service_serial_OBJECTS)
bluetoothd_service_serial_LDADD = $(LDADD)
@@ -258,7 +260,10 @@
@CONFIGFILES_TRUE@@SERIALSERVICE_TRUE at confdir = $(sysconfdir)/bluetooth
@CONFIGFILES_TRUE@@SERIALSERVICE_TRUE at conf_DATA = serial.service
@SERIALSERVICE_TRUE at servicedir = $(libdir)/bluetooth
- at SERIALSERVICE_TRUE@bluetoothd_service_serial_SOURCES = main.c manager.h manager.c
+ at SERIALSERVICE_TRUE@bluetoothd_service_serial_SOURCES = main.c \
+ at SERIALSERVICE_TRUE@ manager.h manager.c port.h port.c \
+ at SERIALSERVICE_TRUE@ error.h error.c storage.h storage.c
+
@SERIALSERVICE_TRUE at LDADD = $(top_builddir)/common/libhelper.a \
@SERIALSERVICE_TRUE@ @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
@@ -337,8 +342,11 @@
distclean-compile:
-rm -f *.tab.c
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/error.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/main.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/manager.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/port.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/storage.Po at am__quote@
.c.o:
@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
Added: bluez-utils/branches/upstream/current/serial/error.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/error.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/serial/error.c (added)
+++ bluez-utils/branches/upstream/current/serial/error.c Wed Jul 4 13:37:57 2007
@@ -1,0 +1,98 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "error.h"
+
+#define SERIAL_ERROR_INTERFACE "org.bluez.serial.Error"
+
+DBusHandlerResult err_connection_canceled(DBusConnection *conn,
+ DBusMessage *msg)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ SERIAL_ERROR_INTERFACE".ConnectionCanceled",
+ "Connection creation canceled"));
+}
+
+DBusHandlerResult err_connection_failed(DBusConnection *conn,
+ DBusMessage *msg, const char *str)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ SERIAL_ERROR_INTERFACE".ConnectionAttemptFailed", str));
+}
+
+DBusHandlerResult err_connection_in_progress(DBusConnection *conn,
+ DBusMessage *msg)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ SERIAL_ERROR_INTERFACE".ConnectionInProgress",
+ "Connection creation in progress"));
+}
+
+DBusHandlerResult err_connection_not_in_progress(DBusConnection *conn,
+ DBusMessage *msg)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ SERIAL_ERROR_INTERFACE".ConnectionNotInProgress",
+ "Connection creation not in progress"));
+}
+
+DBusHandlerResult err_does_not_exist(DBusConnection *conn,
+ DBusMessage *msg, const char *str)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ SERIAL_ERROR_INTERFACE ".DoesNotExist", str));
+}
+
+DBusHandlerResult err_failed(DBusConnection *conn,
+ DBusMessage *msg, const char *str)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ SERIAL_ERROR_INTERFACE ".Failed", str));
+}
+
+DBusHandlerResult err_invalid_args(DBusConnection *conn,
+ DBusMessage *msg, const char *str)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ SERIAL_ERROR_INTERFACE ".InvalidArguments", str));
+}
+
+DBusHandlerResult err_not_supported(DBusConnection *conn,
+ DBusMessage *msg)
+{
+ return send_message_and_unref(conn,
+ dbus_message_new_error(msg,
+ SERIAL_ERROR_INTERFACE ".NotSupported",
+ "The service is not supported by the remote device"));
+}
Added: bluez-utils/branches/upstream/current/serial/error.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/error.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/serial/error.h (added)
+++ bluez-utils/branches/upstream/current/serial/error.h Wed Jul 4 13:37:57 2007
@@ -1,0 +1,41 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <dbus.h>
+
+DBusHandlerResult err_connection_canceled(DBusConnection *conn,
+ DBusMessage *msg);
+DBusHandlerResult err_connection_failed(DBusConnection *conn,
+ DBusMessage *msg, const char *str);
+DBusHandlerResult err_connection_in_progress(DBusConnection *conn,
+ DBusMessage *msg);
+DBusHandlerResult err_connection_not_in_progress(DBusConnection *conn,
+ DBusMessage *msg);
+DBusHandlerResult err_does_not_exist(DBusConnection *conn,
+ DBusMessage *msg, const char *str);
+DBusHandlerResult err_failed(DBusConnection *conn,
+ DBusMessage *msg, const char *str);
+DBusHandlerResult err_invalid_args(DBusConnection *conn,
+ DBusMessage *msg, const char *str);
+DBusHandlerResult err_not_supported(DBusConnection *conn,
+ DBusMessage *msg);
Modified: bluez-utils/branches/upstream/current/serial/manager.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/manager.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/serial/manager.c (original)
+++ bluez-utils/branches/upstream/current/serial/manager.c Wed Jul 4 13:37:57 2007
@@ -25,6 +25,8 @@
#include <config.h>
#endif
+#include <ctype.h>
+#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
@@ -46,36 +48,31 @@
#include "dbus.h"
#include "dbus-helper.h"
#include "logging.h"
-
+#include "textfile.h"
+
+#include "error.h"
+#include "port.h"
+#include "storage.h"
#include "manager.h"
-#define SERIAL_MANAGER_PATH "/org/bluez/serial"
-#define SERIAL_MANAGER_INTERFACE "org.bluez.serial.Manager"
-#define SERIAL_ERROR_INTERFACE "org.bluez.serial.Error"
-
#define BASE_UUID "00000000-0000-1000-8000-00805F9B34FB"
/* Waiting for udev to create the device node */
-#define MAX_OPEN_TRIES 5
-#define OPEN_WAIT 300 /* ms */
-
-struct rfcomm_node {
- int16_t id; /* RFCOMM device id */
- char *name; /* RFCOMM device name */
- DBusConnection *conn; /* for name listener handling */
- char *owner; /* Bus name */
- GIOChannel *io; /* Connected node IO Channel */
- guint io_id; /* IO Channel ID */
-};
+#define MAX_OPEN_TRIES 5
+#define OPEN_WAIT 300 /* ms */
struct pending_connect {
DBusConnection *conn;
DBusMessage *msg;
+ DBusPendingCall *pcall; /* Pending get handles/records */
char *bda; /* Destination address */
char *adapter_path; /* Adapter D-Bus path */
char *pattern; /* Connection request pattern */
bdaddr_t src;
uint8_t channel;
+ guint io_id; /* GIOChannel watch id */
+ GIOChannel *io; /* GIOChannel for RFCOMM connect */
+ char *dev; /* tty device name */
int id; /* RFCOMM device id */
int ntries; /* Open attempts */
int canceled; /* Operation canceled */
@@ -101,7 +98,6 @@
};
static DBusConnection *connection = NULL;
-static GSList *connected_nodes = NULL;
static GSList *pending_connects = NULL;
static int rfcomm_ctl = -1;
@@ -117,35 +113,17 @@
g_free(pc->pattern);
if (pc->adapter_path)
g_free(pc->adapter_path);
+ if (pc->pcall)
+ dbus_pending_call_unref(pc->pcall);
+ if (pc->dev)
+ g_free(pc->dev);
+ if (pc->io_id > 0)
+ g_source_remove(pc->io_id);
+ if (pc->io) {
+ g_io_channel_close(pc->io);
+ g_io_channel_unref(pc->io);
+ }
g_free(pc);
-}
-
-static void rfcomm_node_free(struct rfcomm_node *node)
-{
- if (node->name)
- g_free(node->name);
- if (node->conn)
- dbus_connection_unref(node->conn);
- if (node->owner)
- g_free(node->owner);
- if (node->io) {
- g_source_remove(node->io_id);
- g_io_channel_unref(node->io);
- }
- g_free(node);
-}
-
-static struct rfcomm_node *find_node_by_name(const char *name)
-{
- GSList *l;
-
- for (l = connected_nodes; l != NULL; l = l->next) {
- struct rfcomm_node *node = l->data;
- if (!strcmp(node->name, name))
- return node;
- }
-
- return NULL;
}
static struct pending_connect *find_pending_connect_by_pattern(const char *bda,
@@ -164,6 +142,119 @@
return NULL;
}
+static void transaction_owner_exited(const char *name, void *data)
+{
+ GSList *l, *tmp = NULL;
+ debug("transaction owner %s exited", name);
+
+ /* Clean all pending calls that belongs to this owner */
+ for (l = pending_connects; l != NULL; l = l->next) {
+ struct pending_connect *pc = l->data;
+ if (strcmp(name, dbus_message_get_sender(pc->msg)) != 0) {
+ tmp = g_slist_append(tmp, pc);
+ continue;
+ }
+
+ if (pc->pcall)
+ dbus_pending_call_cancel(pc->pcall);
+
+ if (pc->id >= 0)
+ rfcomm_release(pc->id);
+
+ pending_connect_free(pc);
+ }
+
+ g_slist_free(pending_connects);
+ pending_connects = tmp;
+}
+
+static void pending_connect_remove(struct pending_connect *pc)
+{
+ /* Remove the connection request owner */
+ name_listener_remove(pc->conn, dbus_message_get_sender(pc->msg),
+ (name_cb_t) transaction_owner_exited, NULL);
+
+ pending_connects = g_slist_remove(pending_connects, pc);
+ pending_connect_free(pc);
+}
+
+static void open_notify(int fd, int err, struct pending_connect *pc)
+{
+ DBusMessage *reply;
+ bdaddr_t dst;
+
+ if (err) {
+ /* Max tries exceeded */
+ rfcomm_release(pc->id);
+ err_connection_failed(pc->conn, pc->msg, strerror(err));
+ return;
+ }
+
+ if (pc->canceled) {
+ rfcomm_release(pc->id);
+ err_connection_canceled(pc->conn, pc->msg);
+ return;
+ }
+
+ /* Reply to the requestor */
+ reply = dbus_message_new_method_return(pc->msg);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &pc->dev,
+ DBUS_TYPE_INVALID);
+ send_message_and_unref(pc->conn, reply);
+
+ /* Send the D-Bus signal */
+ dbus_connection_emit_signal(pc->conn, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE, "ServiceConnected" ,
+ DBUS_TYPE_STRING, &pc->dev,
+ DBUS_TYPE_INVALID);
+
+ str2ba(pc->bda, &dst);
+
+ /* Add the RFCOMM connection listener */
+ port_add_listener(pc->conn, pc->id, &dst, fd,
+ pc->dev, dbus_message_get_sender(pc->msg));
+}
+
+static gboolean open_continue(struct pending_connect *pc)
+{
+ int fd;
+
+ if (!g_slist_find(pending_connects, pc))
+ return FALSE; /* Owner exited */
+
+ fd = open(pc->dev, O_RDONLY | O_NOCTTY);
+ if (fd < 0) {
+ int err = errno;
+ error("Could not open %s: %s (%d)",
+ pc->dev, strerror(err), err);
+ if (++pc->ntries >= MAX_OPEN_TRIES) {
+ /* Reporting error */
+ open_notify(fd, err, pc);
+ pending_connect_remove(pc);
+ return FALSE;
+ }
+ return TRUE;
+ }
+ /* Connection succeeded */
+ open_notify(fd, 0, pc);
+ pending_connect_remove(pc);
+ return FALSE;
+}
+
+int port_open(struct pending_connect *pc)
+{
+ int fd;
+
+ fd = open(pc->dev, O_RDONLY | O_NOCTTY);
+ if (fd < 0) {
+ g_timeout_add(OPEN_WAIT, (GSourceFunc) open_continue, pc);
+ return -EINPROGRESS;
+ }
+
+ return fd;
+}
+
static uint16_t str2class(const char *pattern)
{
int i;
@@ -176,98 +267,19 @@
return 0;
}
-static DBusHandlerResult err_connection_failed(DBusConnection *conn,
- DBusMessage *msg, const char *str)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- SERIAL_ERROR_INTERFACE".ConnectionAttemptFailed", str));
-}
-
-static DBusHandlerResult err_connection_canceled(DBusConnection *conn,
- DBusMessage *msg)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- SERIAL_ERROR_INTERFACE".ConnectionCanceled",
- "Connection creation canceled"));
-}
-
-static DBusHandlerResult err_connection_in_progress(DBusConnection *conn,
- DBusMessage *msg)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- SERIAL_ERROR_INTERFACE".ConnectionInProgress",
- "Connection creation in progress"));
-}
-
-static DBusHandlerResult err_connection_not_in_progress(DBusConnection *conn,
- DBusMessage *msg)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- SERIAL_ERROR_INTERFACE".ConnectionNotInProgress",
- "Connection creation not in progress"));
-}
-
-static DBusHandlerResult err_does_not_exist(DBusConnection *conn,
- DBusMessage *msg, const char *str)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- SERIAL_ERROR_INTERFACE ".DoesNotExist", str));
-}
-
-static DBusHandlerResult err_failed(DBusConnection *conn,
- DBusMessage *msg, const char *str)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- SERIAL_ERROR_INTERFACE ".Failed", str));
-}
-
-static DBusHandlerResult err_invalid_args(DBusConnection *conn,
- DBusMessage *msg, const char *str)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- SERIAL_ERROR_INTERFACE ".InvalidArguments", str));
-}
-
-static DBusHandlerResult err_not_authorized(DBusConnection *conn,
- DBusMessage *msg)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- SERIAL_ERROR_INTERFACE ".NotAuthorized",
- "Owner not allowed"));
-}
-
-static DBusHandlerResult err_not_supported(DBusConnection *conn,
- DBusMessage *msg)
-{
- return send_message_and_unref(conn,
- dbus_message_new_error(msg,
- SERIAL_ERROR_INTERFACE ".NotSupported",
- "The service is not supported by the remote device"));
-}
-
-static int rfcomm_release(int16_t id)
+int rfcomm_release(int16_t id)
{
struct rfcomm_dev_req req;
memset(&req, 0, sizeof(req));
req.dev_id = id;
-#if 0
/*
* We are hitting a kernel bug inside RFCOMM code when
* RFCOMM_HANGUP_NOW bit is set on request's flags passed to
* ioctl(RFCOMMRELEASEDEV)!
*/
req.flags = (1 << RFCOMM_HANGUP_NOW);
-#endif
if (ioctl(rfcomm_ctl, RFCOMMRELEASEDEV, &req) < 0) {
int err = errno;
@@ -279,168 +291,62 @@
return 0;
}
-static void connect_service_exited(const char *name, struct rfcomm_node *node)
-{
- debug("Connect requestor %s exited. Releasing %s node",
- name, node->name);
-
- rfcomm_release(node->id);
-
- dbus_connection_emit_signal(node->conn, SERIAL_MANAGER_PATH,
- SERIAL_MANAGER_INTERFACE, "ServiceDisconnected" ,
- DBUS_TYPE_STRING, &node->name,
- DBUS_TYPE_INVALID);
-
- connected_nodes = g_slist_remove(connected_nodes, node);
- rfcomm_node_free(node);
-}
-
-static gboolean rfcomm_disconnect_cb(GIOChannel *io,
- GIOCondition cond, struct rfcomm_node *node)
-{
- debug("RFCOMM node %s was disconnected", node->name);
-
- if (cond & (G_IO_ERR | G_IO_HUP))
- g_io_channel_close(io);
-
- name_listener_remove(node->conn, node->owner,
- (name_cb_t) connect_service_exited, node);
-
- dbus_connection_emit_signal(node->conn, SERIAL_MANAGER_PATH,
- SERIAL_MANAGER_INTERFACE, "ServiceDisconnected" ,
- DBUS_TYPE_STRING, &node->name,
- DBUS_TYPE_INVALID);
-
- connected_nodes = g_slist_remove(connected_nodes, node);
- rfcomm_node_free(node);
-
- return FALSE;
-}
-
-static int add_rfcomm_node(GIOChannel *io, int id, const char *name,
- DBusConnection *conn, const char *owner)
-{
- struct rfcomm_node *node;
-
- node = g_new0(struct rfcomm_node, 1);
- node->id = id;
- node->name = g_strdup(name);
- node->conn = dbus_connection_ref(conn);
- node->owner = g_strdup(owner);
- node->io = io;
-
- node->io_id = g_io_add_watch(io, G_IO_ERR | G_IO_NVAL | G_IO_HUP,
- (GIOFunc) rfcomm_disconnect_cb, node);
-
- connected_nodes = g_slist_append(connected_nodes, node);
-
- return name_listener_add(node->conn, owner,
- (name_cb_t) connect_service_exited, node);
-}
-
-static gboolean rfcomm_connect_cb_continue(struct pending_connect *pc)
-{
- const char *owner = dbus_message_get_sender(pc->msg);
- DBusMessage *reply;
- char node_name[16];
- const char *pname = node_name;
- int fd;
-
- if (pc->canceled) {
- rfcomm_release(pc->id);
- err_connection_canceled(pc->conn, pc->msg);
- goto fail;
- }
-
- /* Check if the caller is still present */
- if (!dbus_bus_name_has_owner(pc->conn, owner, NULL)) {
- error("Connect requestor %s exited", owner);
- rfcomm_release(pc->id);
- goto fail;
- }
-
- snprintf(node_name, sizeof(node_name), "/dev/rfcomm%d", pc->id);
- fd = open(node_name, O_RDONLY | O_NOCTTY);
- if (fd < 0) {
+static int rfcomm_bind(bdaddr_t *src, bdaddr_t *dst, int16_t dev_id, uint8_t ch)
+{
+ struct rfcomm_dev_req req;
+ int id;
+
+ memset(&req, 0, sizeof(req));
+ req.dev_id = dev_id;
+ req.flags = 0;
+ bacpy(&req.src, src);
+ bacpy(&req.dst, dst);
+ req.channel = ch;
+
+ id = ioctl(rfcomm_ctl, RFCOMMCREATEDEV, &req);
+ if (id < 0) {
int err = errno;
- error("Could not open %s: %s (%d)",
- node_name, strerror(err), err);
- if (++pc->ntries >= MAX_OPEN_TRIES) {
- rfcomm_release(pc->id);
- err_connection_failed(pc->conn, pc->msg, strerror(err));
- goto fail;
- }
- return TRUE;
- }
-
- add_rfcomm_node(g_io_channel_unix_new(fd), pc->id,
- node_name, pc->conn, owner);
-
- /* Reply to the requestor */
- reply = dbus_message_new_method_return(pc->msg);
- dbus_message_append_args(reply,
- DBUS_TYPE_STRING, &pname,
- DBUS_TYPE_INVALID);
- send_message_and_unref(pc->conn, reply);
-
- /* Send the D-Bus signal */
- dbus_connection_emit_signal(pc->conn, SERIAL_MANAGER_PATH,
- SERIAL_MANAGER_INTERFACE, "ServiceConnected" ,
- DBUS_TYPE_STRING, &pname,
- DBUS_TYPE_INVALID);
-
-fail:
- pending_connects = g_slist_remove(pending_connects, pc);
- pending_connect_free(pc);
-
- return FALSE;
+ error("RFCOMMCREATEDEV failed: %s (%d)", strerror(err), err);
+ return -err;
+ }
+
+ return id;
}
static gboolean rfcomm_connect_cb(GIOChannel *chan,
GIOCondition cond, struct pending_connect *pc)
{
- DBusMessage *reply;
- char node_name[16];
- const char *pname = node_name;
struct rfcomm_dev_req req;
- int sk, err, fd, close_chan = 1;
+ int sk, err, fd, ret;
+ socklen_t len;
if (pc->canceled) {
err_connection_canceled(pc->conn, pc->msg);
goto fail;
}
+ if (cond & G_IO_NVAL) {
+ /* Avoid close invalid file descriptor */
+ g_io_channel_unref(pc->io);
+ pc->io = NULL;
+ err_connection_canceled(pc->conn, pc->msg);
+ goto fail;
+ }
+
sk = g_io_channel_unix_get_fd(chan);
-
- if (cond & G_IO_NVAL) {
- close_chan = 0;
- err_connection_failed(pc->conn, pc->msg,
- "File descriptor is not open");
- goto fail;
- }
-
- if (cond & (G_IO_ERR | G_IO_HUP)) {
- socklen_t len;
- int ret;
-
- len = sizeof(ret);
- if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) {
- err = errno;
- error("getsockopt(SO_ERROR): %s (%d)",
- strerror(err), err);
- err_connection_failed(pc->conn,
- pc->msg, strerror(err));
- goto fail;
- }
-
- if (ret != 0) {
- error("connect(): %s (%d)", strerror(ret), ret);
- err_connection_failed(pc->conn, pc->msg, strerror(ret));
- goto fail;
- }
-
- error("Hangup on rfcomm socket");
- err_connection_canceled(pc->conn, pc->msg);
+ len = sizeof(ret);
+ if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) {
+ err = errno;
+ error("getsockopt(SO_ERROR): %s (%d)",
+ strerror(err), err);
+ err_connection_failed(pc->conn,
+ pc->msg, strerror(err));
+ goto fail;
+ }
+
+ if (ret != 0) {
+ error("connect(): %s (%d)", strerror(ret), ret);
+ err_connection_failed(pc->conn, pc->msg, strerror(ret));
goto fail;
}
@@ -460,49 +366,25 @@
err_connection_failed(pc->conn, pc->msg, strerror(err));
goto fail;
}
-
-
- snprintf(node_name, sizeof(node_name), "/dev/rfcomm%d", pc->id);
-
- fd = open(node_name, O_RDONLY | O_NOCTTY);
- if (fd < 0) {
- g_timeout_add(OPEN_WAIT,
- (GSourceFunc) rfcomm_connect_cb_continue, pc);
- g_io_channel_close(chan);
+ pc->dev = g_new0(char, 16);
+ snprintf(pc->dev, 16, "/dev/rfcomm%d", pc->id);
+
+ /* Addressing connect port */
+ fd = port_open(pc);
+ if (fd < 0)
+ /* Open in progress: Wait the callback */
return FALSE;
- }
-
- add_rfcomm_node(g_io_channel_unix_new(fd), pc->id, node_name,
- pc->conn, dbus_message_get_sender(pc->msg));
-
- /* Reply to the requestor */
- reply = dbus_message_new_method_return(pc->msg);
- dbus_message_append_args(reply,
- DBUS_TYPE_STRING, &pname,
- DBUS_TYPE_INVALID);
- send_message_and_unref(pc->conn, reply);
-
- /* Send the D-Bus signal */
- dbus_connection_emit_signal(pc->conn, SERIAL_MANAGER_PATH,
- SERIAL_MANAGER_INTERFACE, "ServiceConnected" ,
- DBUS_TYPE_STRING, &pname,
- DBUS_TYPE_INVALID);
-
+
+ open_notify(fd, 0, pc);
fail:
- pending_connects = g_slist_remove(pending_connects, pc);
- pending_connect_free(pc);
-
- if (close_chan)
- g_io_channel_close(chan);
-
+ pending_connect_remove(pc);
return FALSE;
}
static int rfcomm_connect(struct pending_connect *pc)
{
struct sockaddr_rc addr;
- GIOChannel *io;
- int sk, err = 0;
+ int sk, err;
sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
if (sk < 0)
@@ -514,13 +396,12 @@
addr.rc_channel = 0;
if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0)
- return -errno;
+ goto fail;
if (set_nonblocking(sk) < 0)
- return -errno;
-
- io = g_io_channel_unix_new(sk);
-
+ goto fail;
+
+ pc->io = g_io_channel_unix_new(sk);
addr.rc_family = AF_BLUETOOTH;
str2ba(pc->bda, &addr.rc_bdaddr);
addr.rc_channel = pc->channel;
@@ -528,20 +409,26 @@
if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
/* BlueZ returns EAGAIN eventhough it should return EINPROGRESS */
if (!(errno == EAGAIN || errno == EINPROGRESS)) {
- err = errno;
- error("connect() failed: %s (%d)", strerror(err), err);
+ error("connect() failed: %s (%d)",
+ strerror(errno), errno);
goto fail;
}
debug("Connect in progress");
- g_io_add_watch(io, G_IO_OUT | G_IO_ERR | G_IO_NVAL | G_IO_HUP,
- (GIOFunc) rfcomm_connect_cb, pc);
+ pc->io_id = g_io_add_watch(pc->io,
+ G_IO_OUT | G_IO_ERR | G_IO_NVAL | G_IO_HUP,
+ (GIOFunc) rfcomm_connect_cb, pc);
} else {
debug("Connect succeeded with first try");
- (void) rfcomm_connect_cb(io, G_IO_OUT, pc);
- }
+ (void) rfcomm_connect_cb(pc->io, G_IO_OUT, pc);
+ }
+
+ return 0;
fail:
- g_io_channel_unref(io);
+ err = errno;
+ close(sk);
+ errno = err;
+
return -err;
}
@@ -549,7 +436,7 @@
{
struct pending_connect *pc = data;
DBusMessage *reply = dbus_pending_call_steal_reply(call);
- sdp_record_t *rec;
+ sdp_record_t *rec = NULL;
const uint8_t *rec_bin;
sdp_list_t *protos;
DBusError derr;
@@ -597,7 +484,6 @@
}
if (len != scanned || (sdp_get_access_protos(rec, &protos) < 0)) {
- sdp_record_free(rec);
err_not_supported(pc->conn, pc->msg);
goto fail;
}
@@ -606,35 +492,76 @@
sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
sdp_list_free(protos, NULL);
- sdp_record_free(rec);
-
if (ch < 1 || ch > 30) {
error("Channel out of range: %d", ch);
err_not_supported(pc->conn, pc->msg);
goto fail;
}
-
- pc->channel = ch;
- err = rfcomm_connect(pc);
- if (err < 0) {
- error("RFCOMM connection failed");
- err_connection_failed(pc->conn, pc->msg, strerror(-err));
- goto fail;
- }
-
+ if (dbus_message_has_member(pc->msg, "CreatePort")) {
+ char path[MAX_PATH_LENGTH], port_name[16];
+ const char *ppath = path;
+ sdp_data_t *d;
+ char *svcname = NULL;
+ DBusMessage *reply;
+ bdaddr_t dst;
+
+ str2ba(pc->bda, &dst);
+ err = rfcomm_bind(&pc->src, &dst, -1, ch);
+ if (err < 0) {
+ err_failed(pc->conn, pc->msg, strerror(-err));
+ goto fail;
+ }
+ snprintf(port_name, sizeof(port_name), "/dev/rfcomm%d", err);
+
+ d = sdp_data_get(rec, SDP_ATTR_SVCNAME_PRIMARY);
+ if (d) {
+ svcname = g_new0(char, d->unitSize);
+ snprintf(svcname, d->unitSize, "%.*s",
+ d->unitSize, d->val.str);
+ }
+
+ port_store(&pc->src, &dst, err, ch, svcname);
+ if (svcname)
+ g_free(svcname);
+
+ port_register(pc->conn, err, &dst, port_name, path);
+
+ reply = dbus_message_new_method_return(pc->msg);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &ppath,
+ DBUS_TYPE_INVALID);
+ send_message_and_unref(pc->conn, reply);
+
+ dbus_connection_emit_signal(pc->conn, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE, "PortCreated" ,
+ DBUS_TYPE_STRING, &ppath,
+ DBUS_TYPE_INVALID);
+ } else {
+ /* ConnectService */
+ pc->channel = ch;
+ err = rfcomm_connect(pc);
+ if (err < 0) {
+ error("RFCOMM connection failed");
+ err_connection_failed(pc->conn, pc->msg, strerror(-err));
+ goto fail;
+ }
+
+ /* Wait the connect callback */
+ goto done;
+ }
+
+fail:
+ pending_connect_remove(pc);
+done:
+ if (rec)
+ sdp_record_free(rec);
dbus_message_unref(reply);
- return;
-fail:
- dbus_message_unref(reply);
- pending_connects = g_slist_remove(pending_connects, pc);
- pending_connect_free(pc);
}
static int get_record(struct pending_connect *pc, uint32_t handle,
DBusPendingCallNotifyFunction cb)
{
DBusMessage *msg;
- DBusPendingCall *pending;
msg = dbus_message_new_method_call("org.bluez", pc->adapter_path,
"org.bluez.Adapter", "GetRemoteServiceRecord");
@@ -646,14 +573,13 @@
DBUS_TYPE_UINT32, &handle,
DBUS_TYPE_INVALID);
- if (dbus_connection_send_with_reply(pc->conn, msg, &pending, -1) == FALSE) {
+ if (dbus_connection_send_with_reply(pc->conn, msg, &pc->pcall, -1) == FALSE) {
error("Can't send D-Bus message.");
return -1;
}
- dbus_pending_call_set_notify(pending, cb, pc, NULL);
+ dbus_pending_call_set_notify(pc->pcall, cb, pc, NULL);
dbus_message_unref(msg);
- dbus_pending_call_unref(pending);
return 0;
}
@@ -708,15 +634,13 @@
return;
fail:
dbus_message_unref(reply);
- pending_connects = g_slist_remove(pending_connects, pc);
- pending_connect_free(pc);
+ pending_connect_remove(pc);
}
static int get_handles(struct pending_connect *pc, const char *uuid,
DBusPendingCallNotifyFunction cb)
{
DBusMessage *msg;
- DBusPendingCall *pending;
msg = dbus_message_new_method_call("org.bluez", pc->adapter_path,
"org.bluez.Adapter", "GetRemoteServiceHandles");
@@ -728,30 +652,72 @@
DBUS_TYPE_STRING, &uuid,
DBUS_TYPE_INVALID);
- if (dbus_connection_send_with_reply(pc->conn, msg, &pending, -1) == FALSE) {
+ if (dbus_connection_send_with_reply(pc->conn, msg, &pc->pcall, -1) == FALSE) {
error("Can't send D-Bus message.");
return -1;
}
- dbus_pending_call_set_notify(pending, cb, pc, NULL);
+ dbus_pending_call_set_notify(pc->pcall, cb, pc, NULL);
dbus_message_unref(msg);
- dbus_pending_call_unref(pending);
return 0;
}
-static DBusHandlerResult connect_service(DBusConnection *conn,
- DBusMessage *msg, void *data)
-{
- struct pending_connect *pending, *pc;
- DBusError derr;
- bdaddr_t src;
- const char *bda, *pattern;
+static int pattern2uuid128(const char *pattern, char *uuid, size_t size)
+{
+ uint16_t cls;
+
+ /* Friendly name */
+ cls = str2class(pattern);
+ if (cls) {
+ uuid_t uuid16, uuid128;
+
+ sdp_uuid16_create(&uuid16, cls);
+ sdp_uuid16_to_uuid128(&uuid128, &uuid16);
+ sdp_uuid2strn(&uuid128, uuid, size);
+ return 0;
+ }
+
+ /* UUID 128*/
+ if ((strlen(pattern) == 36) &&
+ (strncasecmp(BASE_UUID, pattern, 3) == 0) &&
+ (strncasecmp(BASE_UUID + 8, pattern + 8, 28) == 0)) {
+
+ strncpy(uuid, pattern, size);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int pattern2long(const char *pattern, long *pval)
+{
char *endptr;
long val;
+
+ errno = 0;
+ val = strtol(pattern, &endptr, 0);
+ if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
+ (errno != 0 && val == 0) || (pattern == endptr)) {
+ return -EINVAL;
+ }
+
+ *pval = val;
+
+ return 0;
+}
+
+static DBusHandlerResult create_port(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct pending_connect *pending, *pc;
+ DBusMessage *reply;
+ DBusError derr;
+ bdaddr_t src, dst;
+ char path[MAX_PATH_LENGTH], port_name[16], uuid[37];
+ const char *bda, *pattern, *ppath = path;
+ long val;
int dev_id, err;
- uint16_t cls;
- char tmp[37];
dbus_error_init(&derr);
if (!dbus_message_get_args(msg, &derr,
@@ -776,56 +742,30 @@
pc->conn = dbus_connection_ref(conn);
pc->msg = dbus_message_ref(msg);
pc->bda = g_strdup(bda);
+ pc->id = -1;
pc->pattern = g_strdup(pattern);
pc->adapter_path = g_malloc0(16);
snprintf(pc->adapter_path, 16, "/org/bluez/hci%d", dev_id);
- memset(tmp, 0, sizeof(tmp));
-
- /* Friendly name */
- cls = str2class(pattern);
- if (cls) {
- uuid_t uuid16, uuid128;
-
- sdp_uuid16_create(&uuid16, cls);
- sdp_uuid16_to_uuid128(&uuid128, &uuid16);
- sdp_uuid2strn(&uuid128, tmp, sizeof(tmp));
-
- if (get_handles(pc, tmp, handles_reply) < 0) {
+ memset(uuid, 0, sizeof(uuid));
+
+ /* Friendly name or uuid128 */
+ if (pattern2uuid128(pattern, uuid, sizeof(uuid)) == 0) {
+ if (get_handles(pc, uuid, handles_reply) < 0) {
pending_connect_free(pc);
return err_not_supported(conn, msg);
}
pending_connects = g_slist_append(pending_connects, pc);
+ name_listener_add(conn, dbus_message_get_sender(msg),
+ (name_cb_t) transaction_owner_exited, NULL);
return DBUS_HANDLER_RESULT_HANDLED;
}
- /* UUID 128*/
- if (strlen(pattern) == 36) {
- strcpy(tmp, pattern);
- tmp[4] = '0';
- tmp[5] = '0';
- tmp[6] = '0';
- tmp[7] = '0';
-
- if (strcasecmp(BASE_UUID, tmp) != 0) {
- pending_connect_free(pc);
- return err_invalid_args(conn, msg, "invalid UUID");
- }
-
- if (get_handles(pc, pattern, handles_reply) < 0) {
- pending_connect_free(pc);
- return err_not_supported(conn, msg);
- }
- pending_connects = g_slist_append(pending_connects, pc);
- return DBUS_HANDLER_RESULT_HANDLED;
- }
-
- errno = 0;
- val = strtol(pattern, &endptr, 0);
- if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) ||
- (errno != 0 && val == 0) || (pattern == endptr)) {
+ /* Record handle or channel */
+ err = pattern2long(pattern, &val);
+ if (err < 0) {
pending_connect_free(pc);
- return err_invalid_args(conn, msg, "Invalid pattern");
+ return err_invalid_args(conn, msg, "invalid pattern");
}
/* Record handle: starts at 0x10000 */
@@ -841,7 +781,188 @@
return err_not_supported(conn, msg);
}
pending_connects = g_slist_append(pending_connects, pc);
+ name_listener_add(conn, dbus_message_get_sender(msg),
+ (name_cb_t) transaction_owner_exited, NULL);
return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ pending_connect_free(pc);
+ /* RFCOMM Channel range: 1 - 30 */
+ if (val < 1 || val > 30)
+ return err_invalid_args(conn, msg,
+ "invalid RFCOMM channel");
+
+ str2ba(bda, &dst);
+ err = rfcomm_bind(&src, &dst, -1, val);
+ if (err < 0)
+ return err_failed(conn, msg, strerror(-err));
+
+ snprintf(port_name, sizeof(port_name), "/dev/rfcomm%d", err);
+ port_store(&src, &dst, err, val, NULL);
+ port_register(conn, err, &dst, port_name, path);
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &ppath,
+ DBUS_TYPE_INVALID);
+ send_message_and_unref(conn, reply);
+
+ dbus_connection_emit_signal(conn, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE, "PortCreated" ,
+ DBUS_TYPE_STRING, &ppath,
+ DBUS_TYPE_INVALID);
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult list_ports(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, iter_array;
+ char **dev;
+ int i;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_STRING_AS_STRING, &iter_array);
+
+ if (!dbus_connection_list_registered(conn, SERIAL_MANAGER_PATH, &dev))
+ goto done;
+
+ for (i = 0; dev[i]; i++) {
+ char dev_path[MAX_PATH_LENGTH];
+ const char *ppath = dev_path;
+
+ snprintf(dev_path, sizeof(dev_path), "%s/%s",
+ SERIAL_MANAGER_PATH, dev[i]);
+ dbus_message_iter_append_basic(&iter_array,
+ DBUS_TYPE_STRING, &ppath);
+ }
+
+ dbus_free_string_array(dev);
+done:
+ dbus_message_iter_close_container(&iter, &iter_array);
+
+ return send_message_and_unref(conn, reply);
+}
+
+static DBusHandlerResult remove_port(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct rfcomm_dev_info di;
+ DBusError derr;
+ const char *path;
+ int16_t id;
+
+ dbus_error_init(&derr);
+ if (!dbus_message_get_args(msg, &derr,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID)) {
+ err_invalid_args(conn, msg, derr.message);
+ dbus_error_free(&derr);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ if (sscanf(path, SERIAL_MANAGER_PATH"/rfcomm%hd", &id) != 1)
+ return err_does_not_exist(conn, msg, "Invalid RFCOMM node");
+
+ di.id = id;
+ if (ioctl(rfcomm_ctl, RFCOMMGETDEVINFO, &di) < 0)
+ return err_does_not_exist(conn, msg, "Invalid RFCOMM node");
+ port_delete(&di.src, &di.dst, id);
+
+ if (port_unregister(path) < 0)
+ return err_does_not_exist(conn, msg, "Invalid RFCOMM node");
+
+ send_message_and_unref(conn,
+ dbus_message_new_method_return(msg));
+
+ dbus_connection_emit_signal(conn, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE, "PortRemoved" ,
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult connect_service(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct pending_connect *pending, *pc;
+ DBusError derr;
+ bdaddr_t src;
+ const char *bda, *pattern;
+ long val;
+ int dev_id, err;
+ char uuid[37];
+
+ dbus_error_init(&derr);
+ if (!dbus_message_get_args(msg, &derr,
+ DBUS_TYPE_STRING, &bda,
+ DBUS_TYPE_STRING, &pattern,
+ DBUS_TYPE_INVALID)) {
+ err_invalid_args(conn, msg, derr.message);
+ dbus_error_free(&derr);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
+ pending = find_pending_connect_by_pattern(bda, pattern);
+ if (pending)
+ return err_connection_in_progress(conn, msg);
+
+ dev_id = hci_get_route(NULL);
+ if ((dev_id < 0) || (hci_devba(dev_id, &src) < 0))
+ return err_failed(conn, msg, "Adapter not available");
+
+ pc = g_new0(struct pending_connect, 1);
+ bacpy(&pc->src, &src);
+ pc->conn = dbus_connection_ref(conn);
+ pc->msg = dbus_message_ref(msg);
+ pc->bda = g_strdup(bda);
+ pc->id = -1;
+ pc->pattern = g_strdup(pattern);
+ pc->adapter_path = g_malloc0(16);
+ snprintf(pc->adapter_path, 16, "/org/bluez/hci%d", dev_id);
+
+ memset(uuid, 0, sizeof(uuid));
+
+ /* Friendly name or uuid128 */
+ if (pattern2uuid128(pattern, uuid, sizeof(uuid)) == 0) {
+ if (get_handles(pc, uuid, handles_reply) < 0) {
+ pending_connect_free(pc);
+ return err_not_supported(conn, msg);
+ }
+ pending_connects = g_slist_append(pending_connects, pc);
+ goto done;
+ }
+
+ /* Record handle or channel */
+ err = pattern2long(pattern, &val);
+ if (err < 0) {
+ pending_connect_free(pc);
+ return err_invalid_args(conn, msg, "invalid pattern");
+ }
+
+ /* Record handle: starts at 0x10000 */
+ if (strncasecmp("0x", pattern, 2) == 0) {
+ if (val < 0x10000) {
+ pending_connect_free(pc);
+ return err_invalid_args(conn, msg,
+ "invalid record handle");
+ }
+
+ if (get_record(pc, val, record_reply) < 0) {
+ pending_connect_free(pc);
+ return err_not_supported(conn, msg);
+ }
+ pending_connects = g_slist_append(pending_connects, pc);
+ goto done;
}
/* RFCOMM Channel range: 1 - 30 */
@@ -863,17 +984,19 @@
pending_connect_free(pc);
return err_connection_failed(conn, msg, strerr);
}
+done:
+ name_listener_add(conn, dbus_message_get_sender(msg),
+ (name_cb_t) transaction_owner_exited, NULL);
+
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult disconnect_service(DBusConnection *conn,
DBusMessage *msg, void *data)
{
- DBusMessage *reply;
DBusError derr;
- struct rfcomm_node *node;
const char *name;
- int err;
+ int err, id;
dbus_error_init(&derr);
if (!dbus_message_get_args(msg, &derr,
@@ -884,34 +1007,22 @@
return DBUS_HANDLER_RESULT_HANDLED;
}
- node = find_node_by_name(name);
- if (!node)
- return err_does_not_exist(conn, msg, "Invalid node");
-
- if (strcmp(node->owner, dbus_message_get_sender(msg)) != 0)
- return err_not_authorized(conn, msg);
-
- reply = dbus_message_new_method_return(msg);
- if (!reply)
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
-
- err = rfcomm_release(node->id);
- if (err < 0) {
- dbus_message_unref(reply);
- return err_failed(conn, msg, strerror(-err));
- }
+ if (sscanf(name, "/dev/rfcomm%d", &id) != 1)
+ return err_invalid_args(conn, msg, "invalid RFCOMM node");
+
+ err = port_remove_listener(dbus_message_get_sender(msg), name);
+ if (err < 0)
+ return err_does_not_exist(conn, msg, "Invalid RFCOMM node");
+
+ send_message_and_unref(conn,
+ dbus_message_new_method_return(msg));
dbus_connection_emit_signal(conn, SERIAL_MANAGER_PATH,
SERIAL_MANAGER_INTERFACE, "ServiceDisconnected" ,
- DBUS_TYPE_STRING, &node->name,
- DBUS_TYPE_INVALID);
-
- name_listener_remove(node->conn, node->owner,
- (name_cb_t) connect_service_exited, node);
- connected_nodes = g_slist_remove(connected_nodes, node);
- rfcomm_node_free(node);
-
- return send_message_and_unref(conn, reply);
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult cancel_connect_service(DBusConnection *conn,
@@ -947,12 +1058,8 @@
static void manager_unregister(DBusConnection *conn, void *data)
{
- if (connected_nodes) {
- g_slist_foreach(connected_nodes,
- (GFunc) rfcomm_node_free, NULL);
- g_slist_free(connected_nodes);
- connected_nodes = NULL;
- }
+ char **dev;
+ int i;
if (pending_connects) {
g_slist_foreach(pending_connects,
@@ -960,9 +1067,27 @@
g_slist_free(pending_connects);
pending_connects = NULL;
}
+
+ /* Unregister all paths in serial hierarchy */
+ if (!dbus_connection_list_registered(conn, SERIAL_MANAGER_PATH, &dev))
+ return;
+
+ for (i = 0; dev[i]; i++) {
+ char dev_path[MAX_PATH_LENGTH];
+
+ snprintf(dev_path, sizeof(dev_path), "%s/%s", SERIAL_MANAGER_PATH,
+ dev[i]);
+
+ dbus_connection_destroy_object_path(conn, dev_path);
+ }
+
+ dbus_free_string_array(dev);
}
static DBusMethodVTable manager_methods[] = {
+ { "CreatePort", create_port, "ss", "s" },
+ { "ListPorts", list_ports, "", "as" },
+ { "RemovePort", remove_port, "s", "" },
{ "ConnectService", connect_service, "ss", "s" },
{ "DisconnectService", disconnect_service, "s", "" },
{ "CancelConnectService", cancel_connect_service, "ss", "" },
@@ -972,8 +1097,61 @@
static DBusSignalVTable manager_signals[] = {
{ "ServiceConnected", "s" },
{ "ServiceDisconnected", "s" },
+ { "PortCreated", "s" },
+ { "PortRemoved", "s" },
{ NULL, NULL }
};
+
+static void parse_port(char *key, char *value, void *data)
+{
+ char port_name[16], dst_addr[18];
+ char *src_addr = data;
+ bdaddr_t dst, src;
+ int ch, id;
+
+ memset(dst_addr, 0, sizeof(dst_addr));
+ if (sscanf(key,"%17s#%d", dst_addr, &id) != 2)
+ return;
+
+ if (sscanf(value,"%d:", &ch) != 1)
+ return;
+
+ str2ba(dst_addr, &dst);
+ str2ba(src_addr, &src);
+
+ if (rfcomm_bind(&src, &dst, id, ch) < 0)
+ return;
+
+ snprintf(port_name, sizeof(port_name), "/dev/rfcomm%d", id);
+
+ if (port_register(connection, id, &dst, port_name, NULL) < 0) {
+ rfcomm_release(id);
+ return;
+ }
+}
+
+static void register_stored_ports(void)
+{
+ char filename[PATH_MAX + 1];
+ struct dirent *de;
+ DIR *dir;
+
+ snprintf(filename, PATH_MAX, "%s", STORAGEDIR);
+
+ dir = opendir(filename);
+ if (!dir)
+ return;
+
+ while ((de = readdir(dir)) != NULL) {
+ if (!isdigit(de->d_name[0]))
+ continue;
+ snprintf(filename, PATH_MAX, "%s/%s/serial", STORAGEDIR, de->d_name);
+
+ textfile_foreach(filename, parse_port, de->d_name);
+ }
+
+ closedir(dir);
+}
int serial_init(DBusConnection *conn)
{
@@ -1005,6 +1183,8 @@
info("Registered manager path:%s", SERIAL_MANAGER_PATH);
+ register_stored_ports();
+
return 0;
}
Modified: bluez-utils/branches/upstream/current/serial/manager.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/manager.h?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/serial/manager.h (original)
+++ bluez-utils/branches/upstream/current/serial/manager.h Wed Jul 4 13:37:57 2007
@@ -21,5 +21,11 @@
*
*/
+#define SERIAL_MANAGER_PATH "/org/bluez/serial"
+#define SERIAL_MANAGER_INTERFACE "org.bluez.serial.Manager"
+
+#define MAX_PATH_LENGTH 32
+
int serial_init(DBusConnection *conn);
void serial_exit(void);
+int rfcomm_release(int16_t id);
Added: bluez-utils/branches/upstream/current/serial/port.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/port.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/serial/port.c (added)
+++ bluez-utils/branches/upstream/current/serial/port.c Wed Jul 4 13:37:57 2007
@@ -1,0 +1,300 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <glib.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+
+#include "dbus.h"
+#include "dbus-helper.h"
+#include "logging.h"
+
+#include "error.h"
+#include "manager.h"
+#include "port.h"
+
+#define SERIAL_PORT_INTERFACE "org.bluez.serial.Port"
+
+struct rfcomm_node {
+ int16_t id; /* RFCOMM device id */
+ bdaddr_t dst; /* Destination address */
+ char *name; /* RFCOMM device name */
+ DBusConnection *conn; /* for name listener handling */
+ char *owner; /* Bus name */
+ GIOChannel *io; /* Connected node IO Channel */
+ guint io_id; /* IO Channel ID */
+};
+
+static GSList *connected_nodes = NULL;
+static GSList *bound_nodes = NULL;
+
+static struct rfcomm_node *find_node_by_name(GSList *nodes, const char *name)
+{
+ GSList *l;
+
+ for (l = nodes; l != NULL; l = l->next) {
+ struct rfcomm_node *node = l->data;
+ if (!strcmp(node->name, name))
+ return node;
+ }
+
+ return NULL;
+}
+
+static DBusHandlerResult port_get_address(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct rfcomm_node *node = data;
+ DBusMessage *reply;
+ char bda[18];
+ const char *pbda = bda;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ ba2str(&node->dst, bda);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &pbda,
+ DBUS_TYPE_INVALID);
+ return send_message_and_unref(conn, reply);
+
+}
+
+static DBusHandlerResult port_get_info(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct rfcomm_node *node = data;
+ DBusMessage *reply;
+ DBusMessageIter iter, dict;
+ char bda[18];
+ const char *pbda = bda;
+
+ reply = dbus_message_new_method_return(msg);
+ if (!reply)
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dbus_message_iter_append_dict_entry(&dict, "name",
+ DBUS_TYPE_STRING, &node->name);
+
+ ba2str(&node->dst, bda);
+ dbus_message_iter_append_dict_entry(&dict, "address",
+ DBUS_TYPE_STRING, &pbda);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return send_message_and_unref(conn, reply);
+}
+
+static DBusMethodVTable port_methods[] = {
+ { "GetAddress", port_get_address, "", "s" },
+ { "GetInfo", port_get_info, "", "{sv}" },
+ { NULL, NULL, NULL, NULL },
+};
+
+static DBusSignalVTable port_signals[] = {
+ { NULL, NULL }
+};
+
+static void rfcomm_node_free(struct rfcomm_node *node)
+{
+ if (node->name)
+ g_free(node->name);
+ if (node->conn)
+ dbus_connection_unref(node->conn);
+ if (node->owner)
+ g_free(node->owner);
+ if (node->io) {
+ g_source_remove(node->io_id);
+ g_io_channel_close(node->io);
+ g_io_channel_unref(node->io);
+ }
+ rfcomm_release(node->id);
+ g_free(node);
+}
+
+static void connection_owner_exited(const char *name, struct rfcomm_node *node)
+{
+ debug("Connect requestor %s exited. Releasing %s node",
+ name, node->name);
+
+ dbus_connection_emit_signal(node->conn, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE, "ServiceDisconnected" ,
+ DBUS_TYPE_STRING, &node->name,
+ DBUS_TYPE_INVALID);
+
+ connected_nodes = g_slist_remove(connected_nodes, node);
+ rfcomm_node_free(node);
+}
+
+static gboolean rfcomm_disconnect_cb(GIOChannel *io,
+ GIOCondition cond, struct rfcomm_node *node)
+{
+ debug("RFCOMM node %s was disconnected", node->name);
+
+ name_listener_remove(node->conn, node->owner,
+ (name_cb_t) connection_owner_exited, node);
+
+ dbus_connection_emit_signal(node->conn, SERIAL_MANAGER_PATH,
+ SERIAL_MANAGER_INTERFACE, "ServiceDisconnected" ,
+ DBUS_TYPE_STRING, &node->name,
+ DBUS_TYPE_INVALID);
+
+ connected_nodes = g_slist_remove(connected_nodes, node);
+ rfcomm_node_free(node);
+
+ return FALSE;
+}
+
+static void port_handler_unregister(DBusConnection *conn, void *data)
+{
+ struct rfcomm_node *node = data;
+
+ debug("Unregistered serial port: %s", node->name);
+
+ bound_nodes = g_slist_remove(bound_nodes, node);
+ rfcomm_node_free(node);
+}
+
+int port_add_listener(DBusConnection *conn, int16_t id, bdaddr_t *dst,
+ int fd, const char *name, const char *owner)
+{
+ struct rfcomm_node *node;
+
+ node = g_new0(struct rfcomm_node, 1);
+ bacpy(&node->dst, dst);
+ node->id = id;
+ node->name = g_strdup(name);
+ node->conn = dbus_connection_ref(conn);
+ node->owner = g_strdup(owner);
+ node->io = g_io_channel_unix_new(fd);
+ node->io_id = g_io_add_watch(node->io, G_IO_ERR | G_IO_NVAL | G_IO_HUP,
+ (GIOFunc) rfcomm_disconnect_cb, node);
+
+ connected_nodes = g_slist_append(connected_nodes, node);
+
+ /* Service connection listener */
+ return name_listener_add(conn, owner,
+ (name_cb_t) connection_owner_exited, node);
+}
+
+int port_remove_listener(const char *owner, const char *name)
+{
+ struct rfcomm_node *node;
+
+ node = find_node_by_name(connected_nodes, name);
+ if (!node)
+ return -ENOENT;
+ if (strcmp(node->owner, owner) != 0)
+ return -EPERM;
+
+ name_listener_remove(node->conn, owner,
+ (name_cb_t) connection_owner_exited, node);
+
+ connected_nodes = g_slist_remove(connected_nodes, node);
+ rfcomm_node_free(node);
+
+ return 0;
+}
+
+int port_register(DBusConnection *conn, int16_t id, bdaddr_t *dst,
+ const char *name, char *ppath)
+{
+ char path[MAX_PATH_LENGTH];
+ struct rfcomm_node *node;
+
+ node = g_new0(struct rfcomm_node, 1);
+ bacpy(&node->dst, dst);
+ node->id = id;
+ node->name = g_strdup(name);
+ node->conn = dbus_connection_ref(conn);
+
+ snprintf(path, MAX_PATH_LENGTH, "%s/rfcomm%hd", SERIAL_MANAGER_PATH, id);
+
+ if (!dbus_connection_create_object_path(conn, path, node,
+ port_handler_unregister)) {
+ error("D-Bus failed to register %s path", path);
+ rfcomm_node_free(node);
+ return -1;
+ }
+
+ if (!dbus_connection_register_interface(conn, path,
+ SERIAL_PORT_INTERFACE,
+ port_methods,
+ port_signals, NULL)) {
+ error("D-Bus failed to register %s interface",
+ SERIAL_PORT_INTERFACE);
+ dbus_connection_destroy_object_path(conn, path);
+ return -1;
+ }
+
+ info("Registered RFCOMM:%s, path:%s", name, path);
+
+ if (ppath)
+ strcpy(ppath, path);
+
+ bound_nodes = g_slist_append(bound_nodes, node);
+
+ return 0;
+}
+
+int port_unregister(const char *path)
+{
+ struct rfcomm_node *node;
+ char name[16];
+ int16_t id;
+
+ if (sscanf(path, SERIAL_MANAGER_PATH"/rfcomm%hd", &id) != 1)
+ return -ENOENT;
+
+ snprintf(name, sizeof(name), "/dev/rfcomm%hd", id);
+ node = find_node_by_name(bound_nodes, name);
+ if (!node)
+ return -ENOENT;
+
+ dbus_connection_destroy_object_path(node->conn, path);
+
+ return 0;
+}
Added: bluez-utils/branches/upstream/current/serial/port.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/port.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/serial/port.h (added)
+++ bluez-utils/branches/upstream/current/serial/port.h Wed Jul 4 13:37:57 2007
@@ -1,0 +1,32 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+int port_add_listener(DBusConnection *conn, int16_t id, bdaddr_t *dst,
+ int fd, const char *name, const char *owner);
+
+int port_remove_listener(const char *owner, const char *name);
+
+int port_register(DBusConnection *conn, int16_t id, bdaddr_t *dst,
+ const char *name, char *ppath);
+
+int port_unregister(const char *path);
Modified: bluez-utils/branches/upstream/current/serial/serial-api.txt
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/serial-api.txt?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/serial/serial-api.txt (original)
+++ bluez-utils/branches/upstream/current/serial/serial-api.txt Wed Jul 4 13:37:57 2007
@@ -14,9 +14,11 @@
Creates a serial port object.
- Possible errors:org.bluez.serial.Error.AlreadyExists
+ Possible errors:org.bluez.serial.Error.InvalidArguments
+ org.bluez.serial.Error.ConnectionCanceled
+ org.bluez.serial.Error.ConnectionInProgress
+ org.bluez.serial.Error.ConnectionAttemptFailed
org.bluez.serial.Error.NotSupported
- org.bluez.serial.Error.ConnectionAttemptFailed
org.bluez.serial.Error.Failed
void RemovePort(string path) [experimental]
@@ -24,7 +26,6 @@
Removes the serial port object for given path.
Possible errors:org.bluez.serial.Error.DoesNotExist
- org.bluez.serial.Error.Failed
array{string} ListPorts() [experimental]
@@ -37,9 +38,11 @@
device for it. The RFCOMM TTY device is returned.
Possible errors:org.bluez.serial.Error.InvalidArguments
+ org.bluez.serial.Error.ConnectionCanceled
org.bluez.serial.Error.ConnectionInProgress
+ org.bluez.serial.Error.ConnectionAttemptFailed
org.bluez.serial.Error.NotSupported
- org.bluez.serial.Error.ConnectionAttemptFailed
+ org.bluez.serial.Error.Failed
void CancelConnectService(string address, string pattern)
@@ -54,8 +57,7 @@
created via the ConnectService method.
Possible errors:org.bluez.serial.Error.InvalidArguments
- org.bluez.serial.Error.NotAuthorized
- org.bluez.serial.Error.Failed
+ org.bluez.serial.Error.DoesNotExist
Signals void PortCreated(string path) [experimental]
@@ -70,22 +72,12 @@
=============================
Interface org.bluez.serial.Port
-Object path /org/bluez/serial/port*
+Object path /org/bluez/serial/rfcomm*
Methods string GetAddress() [experimental]
Returns the Bluetooth address of the ending point.
- string Connect() [experimental]
+ string GetInfo() [experimental]
- Connects to remote device associated to the port
- object.
-
- Possible errors:org.bluez.serial.Error.ConnectionAttemptFailed
- org.bluez.serial.Error.Failed
-
- void Disconnect() [experimental]
-
- Disconnects from remote device.
-
- Possible errors:org.bluez.serial.Error.Failed
+ Returns the port properties.
Added: bluez-utils/branches/upstream/current/serial/storage.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/storage.c?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/serial/storage.c (added)
+++ bluez-utils/branches/upstream/current/serial/storage.c Wed Jul 4 13:37:57 2007
@@ -1,0 +1,84 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include <glib.h>
+
+#include "logging.h"
+#include "textfile.h"
+
+#include "storage.h"
+
+int port_delete(bdaddr_t *src, bdaddr_t *dst, int16_t id)
+{
+ char filename[PATH_MAX + 1];
+ char src_addr[18], dst_addr[18];
+ char key[32];
+
+ ba2str(src, src_addr);
+ ba2str(dst, dst_addr);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "serial");
+ snprintf(key, sizeof(key), "%s#%hd", dst_addr, id);
+
+ return textfile_del(filename, key);
+}
+
+int port_store(bdaddr_t *src, bdaddr_t *dst, int16_t id,
+ uint8_t ch, const char *svcname)
+{
+ char filename[PATH_MAX + 1];
+ char src_addr[18], dst_addr[18];
+ char key[32];
+ char *value;
+ int size, err;
+
+ if (!svcname)
+ svcname = "Bluetooth RFCOMM port";
+
+ ba2str(src, src_addr);
+ ba2str(dst, dst_addr);
+
+ create_name(filename, PATH_MAX, STORAGEDIR, src_addr, "serial");
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ size = strlen(svcname) + 3;
+ value = g_malloc0(size);
+
+ snprintf(key, 32, "%s#%hd", dst_addr, id);
+ snprintf(value, size, "%d:%s", ch, svcname);
+
+ err = textfile_put(filename, key, value);
+ g_free(value);
+
+ return err;
+}
Added: bluez-utils/branches/upstream/current/serial/storage.h
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/serial/storage.h?rev=480&op=file
==============================================================================
--- bluez-utils/branches/upstream/current/serial/storage.h (added)
+++ bluez-utils/branches/upstream/current/serial/storage.h Wed Jul 4 13:37:57 2007
@@ -1,0 +1,26 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2004-2007 Marcel Holtmann <marcel at holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+int port_delete(bdaddr_t *src, bdaddr_t *dst, int16_t id);
+int port_store(bdaddr_t *src, bdaddr_t *dst, int16_t id,
+ uint8_t ch, const char *svcname);
Modified: bluez-utils/branches/upstream/current/test/apitest
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/test/apitest?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/test/apitest (original)
+++ bluez-utils/branches/upstream/current/test/apitest Wed Jul 4 13:37:57 2007
@@ -145,7 +145,8 @@
for path in dev_signals_filter:
self.bus.add_signal_receiver(self.dev_signal_handler,
signal, 'org.bluez.Adapter',
- 'org.bluez', path)
+ 'org.bluez', path,
+ message_keyword='dbus_message')
except dbus.DBusException, e:
print 'Failed to setup signal handler for device path: %s' % e
sys.exit(1)
@@ -179,7 +180,7 @@
for cmd in dev_cmds:
print '\t%s' % cmd
- @dbus.decorators.explicitly_pass_message
+ #@dbus.decorators.explicitly_pass_message
def dev_signal_handler(*args, **keywords):
dbus_message = keywords["dbus_message"]
print '%s - %s: ' % (dbus_message.get_member(), dbus_message.get_path()),
@@ -187,7 +188,7 @@
print '%s ' % arg,
print
- @dbus.decorators.explicitly_pass_message
+ #@dbus.decorators.explicitly_pass_message
def mgr_signal_handler(*args, **keywords):
dbus_message = keywords["dbus_message"]
print '%s: ' % dbus_message.get_member()
@@ -414,7 +415,7 @@
self.dbus_dev_sig_setup()
print 'Listening for events...'
- if self.cmd in mgr_cmds:
+ elif self.cmd in mgr_cmds:
try:
self.dbus_mgr_setup()
except dbus.DBusException, e:
Modified: bluez-utils/branches/upstream/current/test/l2test.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/test/l2test.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/test/l2test.c (original)
+++ bluez-utils/branches/upstream/current/test/l2test.c Wed Jul 4 13:37:57 2007
@@ -348,6 +348,7 @@
}
/* Set new options */
+ opts.omtu = omtu;
opts.imtu = imtu;
if (flowctl)
opts.mode = 2;
Modified: bluez-utils/branches/upstream/current/tools/csr.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/tools/csr.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/tools/csr.c (original)
+++ bluez-utils/branches/upstream/current/tools/csr.c Wed Jul 4 13:37:57 2007
@@ -358,6 +358,7 @@
{ 2622, "Marcel 3 (2005-10-27)" },
{ 3326, "Marcel 4 (2006-06-16)" },
{ 3612, "Marcel 5 (2006-10-24)" },
+ { 4509, "Marcel 6 (2007-06-11)" },
{ 195, "Sniff 1 (2001-11-27)" },
{ 220, "Sniff 2 (2002-01-03)" },
{ 269, "Sniff 3 (2002-02-22)" },
Modified: bluez-utils/branches/upstream/current/tools/hciattach.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/tools/hciattach.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/tools/hciattach.c (original)
+++ bluez-utils/branches/upstream/current/tools/hciattach.c Wed Jul 4 13:37:57 2007
@@ -951,6 +951,29 @@
return -1;
}
+ if (u->bdaddr != NULL) {
+ /* Set BD_ADDR */
+ memset(cmd, 0, sizeof(cmd));
+ memset(resp, 0, sizeof(resp));
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x01;
+ cmd[2] = 0xfc;
+ cmd[3] = 0x06;
+ str2ba(u->bdaddr, (bdaddr_t *) (cmd + 4));
+
+ /* Send command */
+ if (write(fd, cmd, 10) != 10) {
+ fprintf(stderr, "Failed to write BD_ADDR command\n");
+ return -1;
+ }
+
+ /* Read reply */
+ if ((n = read_hci_event(fd, resp, 10)) < 0) {
+ fprintf(stderr, "Failed to set BD_ADDR\n");
+ return -1;
+ }
+ }
+
/* Read the local version info */
memset(cmd, 0, sizeof(cmd));
memset(resp, 0, sizeof(resp));
@@ -983,7 +1006,7 @@
/* Send command */
if (write(fd, cmd, 4) != 4) {
fprintf(stderr, "Failed to write \"read local supported "
- "commands\" command\n");
+ "commands\" command\n");
return -1;
}
@@ -1010,11 +1033,11 @@
cmd[5] = 0xfa;
break;
case 460800:
- cmd[4] = 0x11;
+ cmd[4] = 0x22;
cmd[5] = 0xfd;
break;
case 921600:
- cmd[4] = 0x65;
+ cmd[4] = 0x55;
cmd[5] = 0xff;
break;
default:
@@ -1103,7 +1126,7 @@
{ "billionton", 0x0279, 0x950b, HCI_UART_BCSP, 115200, 115200, 0, NULL, bcsp },
/* Broadcom BCM2035 */
- { "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 115200, 0, NULL, bcm2035 },
+ { "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, bcm2035 },
{ NULL, 0 }
};
Modified: bluez-utils/branches/upstream/current/tools/hcitool.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/tools/hcitool.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/tools/hcitool.c (original)
+++ bluez-utils/branches/upstream/current/tools/hcitool.c Wed Jul 4 13:37:57 2007
@@ -905,9 +905,11 @@
}
if ((di.features[7] & LMP_EXT_FEAT) && (features[7] & LMP_EXT_FEAT)) {
- if (hci_read_remote_ext_features(dd, handle, 0, &max_page, features, 20000) == 0)
+ if (hci_read_remote_ext_features(dd, handle, 0,
+ &max_page, features, 20000) == 0)
if (max_page > 0)
- printf("\tExtended features: %d pages\n", max_page);
+ printf("\tExtended features: %d page%s\n",
+ max_page, max_page > 1 ? "s" : "");
}
if (cc) {
Modified: bluez-utils/branches/upstream/current/tools/sdptool.c
URL: http://svn.debian.org/wsvn/pkg-bluetooth/bluez-utils/branches/upstream/current/tools/sdptool.c?rev=480&op=diff
==============================================================================
--- bluez-utils/branches/upstream/current/tools/sdptool.c (original)
+++ bluez-utils/branches/upstream/current/tools/sdptool.c Wed Jul 4 13:37:57 2007
@@ -755,10 +755,12 @@
sdp_list_t *attrid_list;
uint32_t range = 0x0000ffff;
sdp_record_t *rec;
+ int ret;
/* Get the old SDP record */
attrid_list = sdp_list_append(NULL, &range);
rec = sdp_service_attr_req(sess, handle, SDP_ATTR_REQ_RANGE, attrid_list);
+ sdp_list_free(attrid_list, NULL);
if (!rec) {
printf("Service get request failed.\n");
@@ -794,11 +796,11 @@
}
/* Update on the server */
- if (sdp_device_record_update(sess, &interface, rec)) {
+ ret = sdp_device_record_update(sess, &interface, rec);
+ if (ret < 0)
printf("Service Record update failed (%d).\n", errno);
- return -1;
- }
- return 0;
+ sdp_record_free(rec);
+ return ret;
}
static struct option set_options[] = {
@@ -867,11 +869,12 @@
uint8_t uuid16 = SDP_UUID16;
uint8_t uint32 = SDP_UINT32;
uint8_t str8 = SDP_TEXT_STR8;
- int i;
+ int i, ret = 0;
/* Get the old SDP record */
attrid_list = sdp_list_append(NULL, &range);
rec = sdp_service_attr_req(session, handle, SDP_ATTR_REQ_RANGE, attrid_list);
+ sdp_list_free(attrid_list, NULL);
if (!rec) {
printf("Service get request failed.\n");
@@ -919,10 +922,9 @@
sdp_attr_replace(rec, attrib, pSequenceHolder);
/* Update on the server */
- if (sdp_device_record_update(session, &interface, rec)) {
+ ret = sdp_device_record_update(session, &interface, rec);
+ if (ret < 0)
printf("Service Record update failed (%d).\n", errno);
- return -1;
- }
} else
printf("Failed to create pSequenceHolder\n");
@@ -932,8 +934,11 @@
free(dtdArray);
free(valueArray);
-
- return 0;
+ free(allocArray);
+
+ sdp_record_free(rec);
+
+ return ret;
}
static struct option seq_options[] = {
More information about the Pkg-bluetooth-commits
mailing list