3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2001-2002 Nokia Corporation
6 * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
7 * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
8 * Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
40 #include "lib/bluetooth.h"
41 #include "lib/l2cap.h"
43 #include "lib/sdp_lib.h"
48 static guint l2cap_id = 0, unix_id = 0;
49 static int l2cap_sock = -1, unix_sock = -1;
52 * SDP server initialization on startup includes creating the
53 * l2cap and unix sockets over which discovery and registration clients
54 * access us respectively
56 static int init_server(uint16_t mtu, int master, int compat)
58 struct l2cap_options opts;
59 struct sockaddr_l2 l2addr;
60 struct sockaddr_un unaddr;
63 /* Register the public browse group root */
64 register_public_browse_group();
66 /* Register the SDP server's service record */
67 register_server_service();
69 /* Create L2CAP socket */
70 l2cap_sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
72 error("opening L2CAP socket: %s", strerror(errno));
76 memset(&l2addr, 0, sizeof(l2addr));
77 l2addr.l2_family = AF_BLUETOOTH;
78 bacpy(&l2addr.l2_bdaddr, BDADDR_ANY);
79 l2addr.l2_psm = htobs(SDP_PSM);
81 if (bind(l2cap_sock, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0) {
82 error("binding L2CAP socket: %s", strerror(errno));
87 int opt = L2CAP_LM_MASTER;
88 if (setsockopt(l2cap_sock, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) {
89 error("setsockopt: %s", strerror(errno));
95 memset(&opts, 0, sizeof(opts));
96 optlen = sizeof(opts);
98 if (getsockopt(l2cap_sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) {
99 error("getsockopt: %s", strerror(errno));
106 if (setsockopt(l2cap_sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) {
107 error("setsockopt: %s", strerror(errno));
112 if (listen(l2cap_sock, 5) < 0) {
113 error("listen: %s", strerror(errno));
122 /* Create local Unix socket */
123 unix_sock = socket(PF_UNIX, SOCK_STREAM, 0);
125 error("opening UNIX socket: %s", strerror(errno));
129 memset(&unaddr, 0, sizeof(unaddr));
130 unaddr.sun_family = AF_UNIX;
131 strcpy(unaddr.sun_path, SDP_UNIX_PATH);
133 unlink(unaddr.sun_path);
135 if (bind(unix_sock, (struct sockaddr *) &unaddr, sizeof(unaddr)) < 0) {
136 error("binding UNIX socket: %s", strerror(errno));
140 if (listen(unix_sock, 5) < 0) {
141 error("listen UNIX socket: %s", strerror(errno));
145 chmod(SDP_UNIX_PATH, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
150 static gboolean io_session_event(GIOChannel *chan, GIOCondition cond, gpointer data)
156 if (cond & G_IO_NVAL)
159 sk = g_io_channel_unix_get_fd(chan);
161 if (cond & (G_IO_HUP | G_IO_ERR)) {
162 sdp_svcdb_collect_all(sk);
166 len = recv(sk, &hdr, sizeof(sdp_pdu_hdr_t), MSG_PEEK);
167 if (len != sizeof(sdp_pdu_hdr_t)) {
168 sdp_svcdb_collect_all(sk);
172 size = sizeof(sdp_pdu_hdr_t) + ntohs(hdr.plen);
177 len = recv(sk, buf, size, 0);
178 /* Check here only that the received message is not empty.
179 * Incorrect length of message should be processed later
180 * inside handle_request() in order to produce ErrorResponse.
183 sdp_svcdb_collect_all(sk);
188 handle_request(sk, buf, len);
193 static gboolean io_accept_event(GIOChannel *chan, GIOCondition cond, gpointer data)
198 if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
201 if (data == &l2cap_sock) {
202 struct sockaddr_l2 addr;
203 socklen_t len = sizeof(addr);
205 nsk = accept(l2cap_sock, (struct sockaddr *) &addr, &len);
206 } else if (data == &unix_sock) {
207 struct sockaddr_un addr;
208 socklen_t len = sizeof(addr);
210 nsk = accept(unix_sock, (struct sockaddr *) &addr, &len);
215 error("Can't accept connection: %s", strerror(errno));
219 io = g_io_channel_unix_new(nsk);
220 g_io_channel_set_close_on_unref(io, TRUE);
222 g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
223 io_session_event, data);
225 g_io_channel_unref(io);
230 int start_sdp_server(uint16_t mtu, uint32_t flags)
232 int compat = flags & SDP_SERVER_COMPAT;
233 int master = flags & SDP_SERVER_MASTER;
236 info("Starting SDP server");
238 if (init_server(mtu, master, compat) < 0) {
239 error("Server initialization failed");
243 io = g_io_channel_unix_new(l2cap_sock);
244 g_io_channel_set_close_on_unref(io, TRUE);
246 l2cap_id = g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
247 io_accept_event, &l2cap_sock);
248 g_io_channel_unref(io);
250 if (compat && unix_sock > fileno(stderr)) {
251 io = g_io_channel_unix_new(unix_sock);
252 g_io_channel_set_close_on_unref(io, TRUE);
254 unix_id = g_io_add_watch(io,
255 G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
256 io_accept_event, &unix_sock);
257 g_io_channel_unref(io);
263 void stop_sdp_server(void)
265 info("Stopping SDP server");
270 g_source_remove(unix_id);
273 g_source_remove(l2cap_id);
275 l2cap_id = unix_id = 0;
276 l2cap_sock = unix_sock = -1;