1 /* $NetBSD: server.c,v 1.1 2008/08/17 13:20:57 plunky Exp $ */
4 * Copyright (c) 2008 Iain Hibbert
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/cdefs.h>
29 __RCSID("$NetBSD: server.c,v 1.1 2008/08/17 13:20:57 plunky Exp $");
31 #include <sys/ioctl.h>
33 #include <bluetooth.h>
41 static struct event server_ev
;
43 static int server_avail
;
45 static void * server_ss
;
46 static uint32_t server_handle
;
48 static void server_open(void);
49 static void server_close(void);
50 static void server_read(int, short, void *);
51 static void server_register(void);
61 * The server_update() function is called whenever the channel count is
62 * changed. We maintain the SDP record and open or close the server socket
66 server_update(int count
)
69 if (server_limit
== 0)
72 log_debug("count %d", count
);
74 server_avail
= UINT8_MAX
- (count
- 1) * UINT8_MAX
/ server_limit
;
75 log_info("Service Availability: %d/%d", server_avail
, UINT8_MAX
);
77 if (server_avail
== 0 && server_fd
!= -1)
80 if (server_avail
> 0 && server_fd
== -1)
90 struct sockaddr_bt sa
;
93 server_fd
= socket(PF_BLUETOOTH
, SOCK_SEQPACKET
, BTPROTO_L2CAP
);
94 if (server_fd
== -1) {
95 log_err("Could not open L2CAP socket: %m");
99 memset(&sa
, 0, sizeof(sa
));
100 sa
.bt_family
= AF_BLUETOOTH
;
101 sa
.bt_len
= sizeof(sa
);
102 sa
.bt_psm
= l2cap_psm
;
103 bdaddr_copy(&sa
.bt_bdaddr
, &local_bdaddr
);
104 if (bind(server_fd
, (struct sockaddr
*)&sa
, sizeof(sa
)) == -1) {
105 log_err("Could not bind server socket: %m");
109 if (setsockopt(server_fd
, BTPROTO_L2CAP
,
110 SO_L2CAP_LM
, &l2cap_mode
, sizeof(l2cap_mode
)) == -1) {
111 log_err("Could not set link mode (0x%4.4x): %m", l2cap_mode
);
116 if (setsockopt(server_fd
, BTPROTO_L2CAP
,
117 SO_L2CAP_IMTU
, &mru
, sizeof(mru
)) == -1) {
118 log_err("Could not set L2CAP IMTU (%d): %m", mru
);
122 if (listen(server_fd
, 0) == -1) {
123 log_err("Could not listen on server socket: %m");
127 event_set(&server_ev
, server_fd
, EV_READ
| EV_PERSIST
, server_read
, NULL
);
128 if (event_add(&server_ev
, NULL
) == -1) {
129 log_err("Could not add server event: %m");
133 log_info("server socket open");
140 event_del(&server_ev
);
144 log_info("server socket closed");
148 * handle connection request
151 server_read(int s
, short ev
, void *arg
)
153 struct sockaddr_bt ra
, la
;
160 fd
= accept(s
, (struct sockaddr
*)&ra
, &len
);
165 if (ioctl(fd
, FIONBIO
, &n
) == -1) {
166 log_err("Could not set NonBlocking IO: %m");
172 if (getsockopt(fd
, BTPROTO_L2CAP
, SO_L2CAP_IMTU
, &mru
, &len
) == -1) {
173 log_err("Could not get L2CAP IMTU: %m");
177 if(mru
< BNEP_MTU_MIN
) {
178 log_err("L2CAP IMTU too small (%d)", mru
);
184 if (getsockopt(fd
, BTPROTO_L2CAP
, SO_L2CAP_OMTU
, &mtu
, &len
) == -1) {
185 log_err("Could not get L2CAP OMTU: %m");
189 if (mtu
< BNEP_MTU_MIN
) {
190 log_err("L2CAP OMTU too small (%d)", mtu
);
196 if (getsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &n
, &len
) == -1) {
197 log_err("Could not get socket send buffer size: %m");
204 if (setsockopt(fd
, SOL_SOCKET
, SO_SNDBUF
, &n
, sizeof(n
)) == -1) {
205 log_err("Could not set socket send buffer size (%d): %m", n
);
212 if (setsockopt(fd
, SOL_SOCKET
, SO_SNDLOWAT
, &n
, sizeof(n
)) == -1) {
213 log_err("Could not set socket low water mark (%d): %m", n
);
219 if (getsockname(fd
, (struct sockaddr
*)&la
, &len
) == -1) {
220 log_err("Could not get socket address: %m");
225 log_info("Accepted connection from %s", bt_ntoa(&ra
.bt_bdaddr
, NULL
));
227 chan
= channel_alloc();
233 chan
->send
= bnep_send
;
234 chan
->recv
= bnep_recv
;
237 b2eaddr(chan
->raddr
, &ra
.bt_bdaddr
);
238 b2eaddr(chan
->laddr
, &la
.bt_bdaddr
);
239 chan
->state
= CHANNEL_WAIT_CONNECT_REQ
;
240 channel_timeout(chan
, 10);
241 if (!channel_open(chan
, fd
)) {
242 chan
->state
= CHANNEL_CLOSED
;
250 server_register(void)
255 if (server_ss
== NULL
) {
256 server_ss
= sdp_open_local(control_path
);
257 if (server_ss
== NULL
|| sdp_error(server_ss
) != 0) {
258 log_err("failed to contact SDP server");
263 memset(&p
, 0, sizeof(p
));
265 p
.load_factor
= server_avail
;
266 p
.security_description
= (l2cap_mode
== 0 ? 0x0000 : 0x0001);
269 rv
= sdp_change_service(server_ss
, server_handle
,
270 (uint8_t *)&p
, sizeof(p
));
272 rv
= sdp_register_service(server_ss
, service_class
,
273 &local_bdaddr
, (uint8_t *)&p
, sizeof(p
), &server_handle
);
276 errno
= sdp_error(server_ss
);
277 log_err("%s: %m", service_name
);