1
/* $Id: bt-proximity-helper.c 2048 2007-11-11 23:18:19Z lennart $ */
4
This file is part of PulseAudio.
6
Copyright 2007 Lennart Poettering
8
PulseAudio is free software; you can redistribute it and/or modify
9
it under the terms of the GNU Lesser General Public License as published
10
by the Free Software Foundation; either version 2 of the License,
11
or (at your option) any later version.
13
PulseAudio is distributed in the hope that it will be useful, but
14
WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
General Public License for more details.
18
You should have received a copy of the GNU Lesser General Public License
19
along with PulseAudio; if not, write to the Free Software
20
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
25
* Small SUID helper that allows us to ping a BT device. Borrows
26
* heavily from bluez-utils' l2ping, which is licensed as GPL2+, too
27
* and comes with a copyright like this:
29
* Copyright (C) 2000-2001 Qualcomm Incorporated
30
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
31
* Copyright (C) 2002-2007 Marcel Holtmann <marcel@holtmann.org>
47
#include <sys/select.h>
49
#include <bluetooth/bluetooth.h>
50
#include <bluetooth/hci.h>
51
#include <bluetooth/hci_lib.h>
52
#include <bluetooth/l2cap.h>
54
#define PING_STRING "PulseAudio"
59
static void update_status(int found) {
60
static int status = -1;
62
if (!found && status != 0)
64
if (found && status <= 0)
71
int main(int argc, char *argv[]) {
72
struct sockaddr_l2 addr;
75
uint8_t buf[L2CAP_CMD_HDR_SIZE + sizeof(PING_STRING)];
93
if ((fd = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP)) < 0) {
94
fprintf(stderr, "socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP) failed: %s", strerror(errno));
98
memset(&addr, 0, sizeof(addr));
99
addr.l2_family = AF_BLUETOOTH;
100
bacpy(&addr.l2_bdaddr, BDADDR_ANY);
102
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
103
fprintf(stderr, "bind() failed: %s", strerror(errno));
107
memset(&addr, 0, sizeof(addr));
108
addr.l2_family = AF_BLUETOOTH;
109
str2ba(argv[1], &addr.l2_bdaddr);
111
if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
113
if (errno == EHOSTDOWN || errno == ECONNRESET || errno == ETIMEDOUT) {
119
fprintf(stderr, "connect() failed: %s", strerror(errno));
128
memset(&packet, 0, sizeof(packet));
129
strcpy((char*) packet.buf + L2CAP_CMD_HDR_SIZE, PING_STRING);
130
packet.hdr.ident = id;
131
packet.hdr.len = htobs(sizeof(PING_STRING));
132
packet.hdr.code = L2CAP_ECHO_REQ;
134
if ((r = send(fd, &packet, sizeof(packet), 0)) < 0) {
136
if (errno == EHOSTDOWN || errno == ECONNRESET || errno == ETIMEDOUT) {
143
fprintf(stderr, "send() failed: %s", strerror(errno));
147
assert(r == sizeof(packet));
149
gettimeofday(&end, NULL);
150
end.tv_sec += TIMEOUT;
153
struct timeval now, delta;
155
gettimeofday(&now, NULL);
157
if (timercmp(&end, &now, <=)) {
164
timersub(&end, &now, &delta);
169
if (select(fd+1, &fds, NULL, NULL, &delta) < 0) {
170
fprintf(stderr, "select() failed: %s", strerror(errno));
174
if ((r = recv(fd, &packet, sizeof(packet), 0)) <= 0) {
176
if (errno == EHOSTDOWN || errno == ECONNRESET || errno == ETIMEDOUT) {
183
fprintf(stderr, "send() failed: %s", r == 0 ? "EOF" : strerror(errno));
187
assert(r >= L2CAP_CMD_HDR_SIZE);
189
if (packet.hdr.ident != id)
192
if (packet.hdr.code == L2CAP_ECHO_RSP || packet.hdr.code == L2CAP_COMMAND_REJ) {