~diwic/ubuntu/lucid/pulseaudio/bugfixes

« back to all changes in this revision

Viewing changes to src/modules/bt-proximity-helper.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel T Chen
  • Date: 2007-12-04 00:56:08 UTC
  • mto: (1.15.1 sid)
  • mto: This revision was merged to the branch mainline in revision 15.
  • Revision ID: james.westby@ubuntu.com-20071204005608-3lzrrrpxi186kgx4
Tags: upstream-0.9.8
ImportĀ upstreamĀ versionĀ 0.9.8

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: bt-proximity-helper.c 2048 2007-11-11 23:18:19Z lennart $ */
 
2
 
 
3
/***
 
4
  This file is part of PulseAudio.
 
5
 
 
6
  Copyright 2007 Lennart Poettering
 
7
 
 
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.
 
12
 
 
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.
 
17
 
 
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
 
21
  USA.
 
22
***/
 
23
 
 
24
/*
 
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:
 
28
 *
 
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>
 
32
 *
 
33
 */
 
34
 
 
35
#ifdef HAVE_CONFIG_H
 
36
#include <config.h>
 
37
#endif
 
38
 
 
39
#undef NDEBUG
 
40
 
 
41
#include <assert.h>
 
42
#include <stdio.h>
 
43
#include <errno.h>
 
44
#include <unistd.h>
 
45
#include <stdlib.h>
 
46
#include <sys/time.h>
 
47
#include <sys/select.h>
 
48
 
 
49
#include <bluetooth/bluetooth.h>
 
50
#include <bluetooth/hci.h>
 
51
#include <bluetooth/hci_lib.h>
 
52
#include <bluetooth/l2cap.h>
 
53
 
 
54
#define PING_STRING "PulseAudio"
 
55
#define IDENT 200
 
56
#define TIMEOUT 4
 
57
#define INTERVAL 2
 
58
 
 
59
static void update_status(int found) {
 
60
    static int status = -1;
 
61
 
 
62
    if (!found && status != 0)
 
63
        printf("-");
 
64
    if (found && status <= 0)
 
65
        printf("+");
 
66
 
 
67
    fflush(stdout);
 
68
    status = !!found;
 
69
}
 
70
 
 
71
int main(int argc, char *argv[]) {
 
72
    struct sockaddr_l2 addr;
 
73
    union {
 
74
        l2cap_cmd_hdr hdr;
 
75
        uint8_t buf[L2CAP_CMD_HDR_SIZE + sizeof(PING_STRING)];
 
76
    }  packet;
 
77
    int fd = -1;
 
78
    uint8_t id = IDENT;
 
79
    int connected = 0;
 
80
 
 
81
    assert(argc == 2);
 
82
 
 
83
    for (;;) {
 
84
        fd_set fds;
 
85
        struct timeval end;
 
86
        ssize_t r;
 
87
 
 
88
        if (!connected) {
 
89
 
 
90
            if (fd >= 0)
 
91
                close(fd);
 
92
 
 
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));
 
95
                goto finish;
 
96
            }
 
97
 
 
98
            memset(&addr, 0, sizeof(addr));
 
99
            addr.l2_family = AF_BLUETOOTH;
 
100
            bacpy(&addr.l2_bdaddr, BDADDR_ANY);
 
101
 
 
102
            if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 
103
                fprintf(stderr, "bind() failed: %s", strerror(errno));
 
104
                goto finish;
 
105
            }
 
106
 
 
107
            memset(&addr, 0, sizeof(addr));
 
108
            addr.l2_family = AF_BLUETOOTH;
 
109
            str2ba(argv[1], &addr.l2_bdaddr);
 
110
 
 
111
            if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 
112
 
 
113
                if (errno == EHOSTDOWN || errno == ECONNRESET || errno == ETIMEDOUT) {
 
114
                    update_status(0);
 
115
                    sleep(INTERVAL);
 
116
                    continue;
 
117
                }
 
118
 
 
119
                fprintf(stderr, "connect() failed: %s", strerror(errno));
 
120
                goto finish;
 
121
            }
 
122
 
 
123
            connected = 1;
 
124
        }
 
125
 
 
126
        assert(connected);
 
127
 
 
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;
 
133
 
 
134
        if ((r = send(fd, &packet, sizeof(packet), 0)) < 0) {
 
135
 
 
136
            if (errno == EHOSTDOWN || errno == ECONNRESET || errno == ETIMEDOUT) {
 
137
                update_status(0);
 
138
                connected = 0;
 
139
                sleep(INTERVAL);
 
140
                continue;
 
141
            }
 
142
 
 
143
            fprintf(stderr, "send() failed: %s", strerror(errno));
 
144
            goto finish;
 
145
        }
 
146
 
 
147
        assert(r == sizeof(packet));
 
148
 
 
149
        gettimeofday(&end, NULL);
 
150
        end.tv_sec += TIMEOUT;
 
151
 
 
152
        for (;;) {
 
153
            struct timeval now, delta;
 
154
 
 
155
            gettimeofday(&now, NULL);
 
156
 
 
157
            if (timercmp(&end, &now, <=)) {
 
158
                update_status(0);
 
159
                connected = 0;
 
160
                sleep(INTERVAL);
 
161
                break;
 
162
            }
 
163
 
 
164
            timersub(&end, &now, &delta);
 
165
 
 
166
            FD_ZERO(&fds);
 
167
            FD_SET(fd, &fds);
 
168
 
 
169
            if (select(fd+1, &fds, NULL, NULL, &delta) < 0) {
 
170
                fprintf(stderr, "select() failed: %s", strerror(errno));
 
171
                goto finish;
 
172
            }
 
173
 
 
174
            if ((r = recv(fd, &packet, sizeof(packet), 0)) <= 0) {
 
175
 
 
176
                if (errno == EHOSTDOWN || errno == ECONNRESET || errno == ETIMEDOUT) {
 
177
                    update_status(0);
 
178
                    connected = 0;
 
179
                    sleep(INTERVAL);
 
180
                    break;
 
181
                }
 
182
 
 
183
                fprintf(stderr, "send() failed: %s", r == 0 ? "EOF" : strerror(errno));
 
184
                goto finish;
 
185
            }
 
186
 
 
187
            assert(r >= L2CAP_CMD_HDR_SIZE);
 
188
 
 
189
            if (packet.hdr.ident != id)
 
190
                continue;
 
191
 
 
192
            if (packet.hdr.code == L2CAP_ECHO_RSP || packet.hdr.code == L2CAP_COMMAND_REJ) {
 
193
 
 
194
                if (++id >= 0xFF)
 
195
                    id = IDENT;
 
196
 
 
197
                update_status(1);
 
198
                sleep(INTERVAL);
 
199
                break;
 
200
            }
 
201
        }
 
202
    }
 
203
 
 
204
finish:
 
205
 
 
206
    if (fd >= 0)
 
207
        close(fd);
 
208
 
 
209
    return 1;
 
210
}