dom/bluetooth/bluez/BluetoothUnixSocketConnector.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=80: */
michael@0 3 /*
michael@0 4 * Copyright 2009, The Android Open Source Project
michael@0 5 *
michael@0 6 * Licensed under the Apache License, Version 2.0 (the "License");
michael@0 7 * you may not use this file except in compliance with the License.
michael@0 8 * You may obtain a copy of the License at
michael@0 9 *
michael@0 10 * http://www.apache.org/licenses/LICENSE-2.0
michael@0 11 *
michael@0 12 * Unless required by applicable law or agreed to in writing, software
michael@0 13 * distributed under the License is distributed on an "AS IS" BASIS,
michael@0 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
michael@0 15 * See the License for the specific language governing permissions and
michael@0 16 * limitations under the License.
michael@0 17 *
michael@0 18 * NOTE: Due to being based on the dbus compatibility layer for
michael@0 19 * android's bluetooth implementation, this file is licensed under the
michael@0 20 * apache license instead of MPL.
michael@0 21 *
michael@0 22 */
michael@0 23
michael@0 24 #include <fcntl.h>
michael@0 25 #include <unistd.h>
michael@0 26 #include <stdlib.h>
michael@0 27 #include <errno.h>
michael@0 28
michael@0 29 #include <sys/socket.h>
michael@0 30 #ifdef MOZ_B2G_BT_BLUEZ
michael@0 31 #include <bluetooth/bluetooth.h>
michael@0 32 #include <bluetooth/l2cap.h>
michael@0 33 #include <bluetooth/rfcomm.h>
michael@0 34 #include <bluetooth/sco.h>
michael@0 35 #endif
michael@0 36 #include "BluetoothUnixSocketConnector.h"
michael@0 37 #include "nsThreadUtils.h"
michael@0 38
michael@0 39 using namespace mozilla::ipc;
michael@0 40 USING_BLUETOOTH_NAMESPACE
michael@0 41
michael@0 42 static const int RFCOMM_SO_SNDBUF = 70 * 1024; // 70 KB send buffer
michael@0 43 static const int L2CAP_SO_SNDBUF = 400 * 1024; // 400 KB send buffer
michael@0 44 static const int L2CAP_SO_RCVBUF = 400 * 1024; // 400 KB receive buffer
michael@0 45 static const int L2CAP_MAX_MTU = 65000;
michael@0 46
michael@0 47 #ifdef MOZ_B2G_BT_BLUEZ
michael@0 48 static
michael@0 49 int get_bdaddr(const char *str, bdaddr_t *ba)
michael@0 50 {
michael@0 51 char *d = ((char*)ba) + 5, *endp;
michael@0 52 for (int i = 0; i < 6; i++) {
michael@0 53 *d-- = strtol(str, &endp, 16);
michael@0 54 MOZ_ASSERT(!(*endp != ':' && i != 5));
michael@0 55 str = endp + 1;
michael@0 56 }
michael@0 57 return 0;
michael@0 58 }
michael@0 59
michael@0 60 static
michael@0 61 void get_bdaddr_as_string(const bdaddr_t *ba, char *str) {
michael@0 62 const uint8_t *b = (const uint8_t *)ba;
michael@0 63 sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
michael@0 64 b[5], b[4], b[3], b[2], b[1], b[0]);
michael@0 65 }
michael@0 66
michael@0 67 #endif
michael@0 68
michael@0 69 BluetoothUnixSocketConnector::BluetoothUnixSocketConnector(
michael@0 70 BluetoothSocketType aType,
michael@0 71 int aChannel,
michael@0 72 bool aAuth,
michael@0 73 bool aEncrypt) : mType(aType)
michael@0 74 , mChannel(aChannel)
michael@0 75 , mAuth(aAuth)
michael@0 76 , mEncrypt(aEncrypt)
michael@0 77 {
michael@0 78 }
michael@0 79
michael@0 80 bool
michael@0 81 BluetoothUnixSocketConnector::SetUp(int aFd)
michael@0 82 {
michael@0 83 #ifdef MOZ_B2G_BT_BLUEZ
michael@0 84 int lm = 0;
michael@0 85 int sndbuf, rcvbuf;
michael@0 86
michael@0 87 /* kernel does not yet support LM for SCO */
michael@0 88 switch (mType) {
michael@0 89 case BluetoothSocketType::RFCOMM:
michael@0 90 lm |= mAuth ? RFCOMM_LM_AUTH : 0;
michael@0 91 lm |= mEncrypt ? RFCOMM_LM_ENCRYPT : 0;
michael@0 92 break;
michael@0 93 case BluetoothSocketType::L2CAP:
michael@0 94 case BluetoothSocketType::EL2CAP:
michael@0 95 lm |= mAuth ? L2CAP_LM_AUTH : 0;
michael@0 96 lm |= mEncrypt ? L2CAP_LM_ENCRYPT : 0;
michael@0 97 break;
michael@0 98 case BluetoothSocketType::SCO:
michael@0 99 break;
michael@0 100 default:
michael@0 101 MOZ_CRASH("Unknown socket type!");
michael@0 102 }
michael@0 103
michael@0 104 if (lm) {
michael@0 105 if (mType == BluetoothSocketType::RFCOMM) {
michael@0 106 if (setsockopt(aFd, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm))) {
michael@0 107 BT_WARNING("setsockopt(RFCOMM_LM) failed, throwing");
michael@0 108 return false;
michael@0 109 }
michael@0 110 } else if (mType == BluetoothSocketType::L2CAP ||
michael@0 111 mType == BluetoothSocketType::EL2CAP) {
michael@0 112 if (setsockopt(aFd, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm))) {
michael@0 113 BT_WARNING("setsockopt(L2CAP_LM) failed, throwing");
michael@0 114 return false;
michael@0 115 }
michael@0 116 }
michael@0 117 }
michael@0 118
michael@0 119 if (mType == BluetoothSocketType::RFCOMM) {
michael@0 120 sndbuf = RFCOMM_SO_SNDBUF;
michael@0 121 if (setsockopt(aFd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
michael@0 122 BT_WARNING("setsockopt(SO_SNDBUF) failed, throwing");
michael@0 123 return false;
michael@0 124 }
michael@0 125 }
michael@0 126
michael@0 127 /* Setting L2CAP socket options */
michael@0 128 if (mType == BluetoothSocketType::L2CAP ||
michael@0 129 mType == BluetoothSocketType::EL2CAP) {
michael@0 130 struct l2cap_options opts;
michael@0 131 socklen_t optlen = sizeof(opts);
michael@0 132 int err;
michael@0 133 err = getsockopt(aFd, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen);
michael@0 134 if (!err) {
michael@0 135 /* setting MTU for [E]L2CAP */
michael@0 136 opts.omtu = opts.imtu = L2CAP_MAX_MTU;
michael@0 137
michael@0 138 /* Enable ERTM for [E]L2CAP */
michael@0 139 if (mType == BluetoothSocketType::EL2CAP) {
michael@0 140 opts.flush_to = 0xffff; /* infinite */
michael@0 141 opts.mode = L2CAP_MODE_ERTM;
michael@0 142 opts.fcs = 1;
michael@0 143 opts.txwin_size = 64;
michael@0 144 opts.max_tx = 10;
michael@0 145 }
michael@0 146
michael@0 147 err = setsockopt(aFd, SOL_L2CAP, L2CAP_OPTIONS, &opts, optlen);
michael@0 148 }
michael@0 149
michael@0 150 /* Set larger SNDBUF & RCVBUF for EL2CAP connections */
michael@0 151 if (mType == BluetoothSocketType::EL2CAP) {
michael@0 152 sndbuf = L2CAP_SO_SNDBUF;
michael@0 153 if (setsockopt(aFd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
michael@0 154 BT_WARNING("setsockopt(SO_SNDBUF) failed, throwing");
michael@0 155 return false;
michael@0 156 }
michael@0 157
michael@0 158 rcvbuf = L2CAP_SO_RCVBUF;
michael@0 159 if (setsockopt(aFd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf))) {
michael@0 160 BT_WARNING("setsockopt(SO_RCVBUF) failed, throwing");
michael@0 161 return false;
michael@0 162 }
michael@0 163 }
michael@0 164 }
michael@0 165 #endif
michael@0 166 return true;
michael@0 167 }
michael@0 168
michael@0 169 bool
michael@0 170 BluetoothUnixSocketConnector::SetUpListenSocket(int aFd)
michael@0 171 {
michael@0 172 // Nothing to do here.
michael@0 173 return true;
michael@0 174 }
michael@0 175
michael@0 176 int
michael@0 177 BluetoothUnixSocketConnector::Create()
michael@0 178 {
michael@0 179 MOZ_ASSERT(!NS_IsMainThread());
michael@0 180 int fd = -1;
michael@0 181
michael@0 182 #ifdef MOZ_B2G_BT_BLUEZ
michael@0 183 switch (mType) {
michael@0 184 case BluetoothSocketType::RFCOMM:
michael@0 185 fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
michael@0 186 break;
michael@0 187 case BluetoothSocketType::SCO:
michael@0 188 fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
michael@0 189 break;
michael@0 190 case BluetoothSocketType::L2CAP:
michael@0 191 fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
michael@0 192 break;
michael@0 193 case BluetoothSocketType::EL2CAP:
michael@0 194 fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_L2CAP);
michael@0 195 break;
michael@0 196 default:
michael@0 197 MOZ_CRASH();
michael@0 198 }
michael@0 199
michael@0 200 if (fd < 0) {
michael@0 201 BT_WARNING("Could not open bluetooth socket!");
michael@0 202 return -1;
michael@0 203 }
michael@0 204
michael@0 205 if (!SetUp(fd)) {
michael@0 206 BT_WARNING("Could not set up socket!");
michael@0 207 return -1;
michael@0 208 }
michael@0 209 #endif
michael@0 210 return fd;
michael@0 211 }
michael@0 212
michael@0 213 bool
michael@0 214 BluetoothUnixSocketConnector::CreateAddr(bool aIsServer,
michael@0 215 socklen_t& aAddrSize,
michael@0 216 sockaddr_any& aAddr,
michael@0 217 const char* aAddress)
michael@0 218 {
michael@0 219 #ifdef MOZ_B2G_BT_BLUEZ
michael@0 220 // Set to BDADDR_ANY, if it's not a server, we'll reset.
michael@0 221 bdaddr_t bd_address_obj = {{0, 0, 0, 0, 0, 0}};
michael@0 222
michael@0 223 if (!aIsServer && aAddress && strlen(aAddress) > 0) {
michael@0 224 if (get_bdaddr(aAddress, &bd_address_obj)) {
michael@0 225 BT_WARNING("Can't get bluetooth address!");
michael@0 226 return false;
michael@0 227 }
michael@0 228 }
michael@0 229
michael@0 230 // Initialize
michael@0 231 memset(&aAddr, 0, sizeof(aAddr));
michael@0 232
michael@0 233 switch (mType) {
michael@0 234 case BluetoothSocketType::RFCOMM:
michael@0 235 struct sockaddr_rc addr_rc;
michael@0 236 aAddrSize = sizeof(addr_rc);
michael@0 237 aAddr.rc.rc_family = AF_BLUETOOTH;
michael@0 238 aAddr.rc.rc_channel = mChannel;
michael@0 239 memcpy(&aAddr.rc.rc_bdaddr, &bd_address_obj, sizeof(bd_address_obj));
michael@0 240 break;
michael@0 241 case BluetoothSocketType::L2CAP:
michael@0 242 case BluetoothSocketType::EL2CAP:
michael@0 243 struct sockaddr_l2 addr_l2;
michael@0 244 aAddrSize = sizeof(addr_l2);
michael@0 245 aAddr.l2.l2_family = AF_BLUETOOTH;
michael@0 246 aAddr.l2.l2_psm = mChannel;
michael@0 247 memcpy(&aAddr.l2.l2_bdaddr, &bd_address_obj, sizeof(bdaddr_t));
michael@0 248 break;
michael@0 249 case BluetoothSocketType::SCO:
michael@0 250 struct sockaddr_sco addr_sco;
michael@0 251 aAddrSize = sizeof(addr_sco);
michael@0 252 aAddr.sco.sco_family = AF_BLUETOOTH;
michael@0 253 memcpy(&aAddr.sco.sco_bdaddr, &bd_address_obj, sizeof(bd_address_obj));
michael@0 254 break;
michael@0 255 default:
michael@0 256 BT_WARNING("Socket type unknown!");
michael@0 257 return false;
michael@0 258 }
michael@0 259 #endif
michael@0 260 return true;
michael@0 261 }
michael@0 262
michael@0 263 void
michael@0 264 BluetoothUnixSocketConnector::GetSocketAddr(const sockaddr_any& aAddr,
michael@0 265 nsAString& aAddrStr)
michael@0 266 {
michael@0 267 #ifdef MOZ_B2G_BT_BLUEZ
michael@0 268 char addr[18];
michael@0 269 switch (mType) {
michael@0 270 case BluetoothSocketType::RFCOMM:
michael@0 271 get_bdaddr_as_string((bdaddr_t*)(&aAddr.rc.rc_bdaddr), addr);
michael@0 272 break;
michael@0 273 case BluetoothSocketType::SCO:
michael@0 274 get_bdaddr_as_string((bdaddr_t*)(&aAddr.sco.sco_bdaddr), addr);
michael@0 275 break;
michael@0 276 case BluetoothSocketType::L2CAP:
michael@0 277 case BluetoothSocketType::EL2CAP:
michael@0 278 get_bdaddr_as_string((bdaddr_t*)(&aAddr.l2.l2_bdaddr), addr);
michael@0 279 break;
michael@0 280 default:
michael@0 281 MOZ_CRASH("Socket should be either RFCOMM or SCO!");
michael@0 282 }
michael@0 283 aAddrStr.AssignASCII(addr);
michael@0 284 #endif
michael@0 285 }

mercurial