blob: d9ff36ae34bf77d1ca1cdb59d9f2edc88672fd85 [file] [log] [blame]
Nick Pelly0b6955a2009-05-26 19:13:43 -07001/*
2 * Copyright 2009, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "BluetoothSocket.cpp"
18
19#include "android_bluetooth_common.h"
Doug Kwan75d086e2011-07-16 19:14:18 -070020#include "android_bluetooth_c.h"
Nick Pelly0b6955a2009-05-26 19:13:43 -070021#include "android_runtime/AndroidRuntime.h"
22#include "JNIHelp.h"
23#include "utils/Log.h"
24#include "cutils/abort_socket.h"
25
26#include <stdlib.h>
27#include <errno.h>
28#include <unistd.h>
29#include <sys/socket.h>
30#include <sys/ioctl.h>
31
32#ifdef HAVE_BLUETOOTH
33#include <bluetooth/bluetooth.h>
34#include <bluetooth/rfcomm.h>
Nick Pelly6a669fa2009-06-02 15:57:18 -070035#include <bluetooth/l2cap.h>
36#include <bluetooth/sco.h>
Nick Pelly0b6955a2009-05-26 19:13:43 -070037#endif
38
Nick Pelly6a669fa2009-06-02 15:57:18 -070039#define TYPE_AS_STR(t) \
40 ((t) == TYPE_RFCOMM ? "RFCOMM" : ((t) == TYPE_SCO ? "SCO" : "L2CAP"))
41
Nick Pelly0b6955a2009-05-26 19:13:43 -070042namespace android {
43
44static jfieldID field_mAuth; /* read-only */
45static jfieldID field_mEncrypt; /* read-only */
Nick Pelly6a669fa2009-06-02 15:57:18 -070046static jfieldID field_mType; /* read-only */
47static jfieldID field_mAddress; /* read-only */
48static jfieldID field_mPort; /* read-only */
Nick Pelly0b6955a2009-05-26 19:13:43 -070049static jfieldID field_mSocketData;
50static jmethodID method_BluetoothSocket_ctor;
51static jclass class_BluetoothSocket;
52
Nick Pelly6a669fa2009-06-02 15:57:18 -070053/* Keep TYPE_RFCOMM etc in sync with BluetoothSocket.java */
54static const int TYPE_RFCOMM = 1;
55static const int TYPE_SCO = 2;
56static const int TYPE_L2CAP = 3; // TODO: Test l2cap code paths
57
Nick Pelly41a0a4a2009-08-31 13:33:06 -070058static const int RFCOMM_SO_SNDBUF = 70 * 1024; // 70 KB send buffer
59
Nick Pellyfbbea2e2011-07-28 17:59:27 -070060static void abortNative(JNIEnv *env, jobject obj);
61static void destroyNative(JNIEnv *env, jobject obj);
62
Nick Pelly0b6955a2009-05-26 19:13:43 -070063static struct asocket *get_socketData(JNIEnv *env, jobject obj) {
64 struct asocket *s =
65 (struct asocket *) env->GetIntField(obj, field_mSocketData);
66 if (!s)
67 jniThrowException(env, "java/io/IOException", "null socketData");
68 return s;
69}
70
71static void initSocketFromFdNative(JNIEnv *env, jobject obj, jint fd) {
72#ifdef HAVE_BLUETOOTH
Steve Block71f2cf12011-10-20 11:56:00 +010073 ALOGV("%s", __FUNCTION__);
Nick Pelly0b6955a2009-05-26 19:13:43 -070074
75 struct asocket *s = asocket_init(fd);
76
77 if (!s) {
Steve Block71f2cf12011-10-20 11:56:00 +010078 ALOGV("asocket_init() failed, throwing");
Nick Pelly0b6955a2009-05-26 19:13:43 -070079 jniThrowIOException(env, errno);
80 return;
81 }
82
83 env->SetIntField(obj, field_mSocketData, (jint)s);
84
85 return;
86#endif
87 jniThrowIOException(env, ENOSYS);
88}
89
90static void initSocketNative(JNIEnv *env, jobject obj) {
91#ifdef HAVE_BLUETOOTH
Steve Block71f2cf12011-10-20 11:56:00 +010092 ALOGV("%s", __FUNCTION__);
Nick Pelly0b6955a2009-05-26 19:13:43 -070093
94 int fd;
95 int lm = 0;
Nick Pelly41a0a4a2009-08-31 13:33:06 -070096 int sndbuf;
Nick Pelly0b6955a2009-05-26 19:13:43 -070097 jboolean auth;
98 jboolean encrypt;
Nick Pelly6a669fa2009-06-02 15:57:18 -070099 jint type;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700100
Nick Pelly6a669fa2009-06-02 15:57:18 -0700101 type = env->GetIntField(obj, field_mType);
102
103 switch (type) {
104 case TYPE_RFCOMM:
105 fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
106 break;
107 case TYPE_SCO:
108 fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
109 break;
110 case TYPE_L2CAP:
111 fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
112 break;
113 default:
114 jniThrowIOException(env, ENOSYS);
115 return;
116 }
117
Nick Pelly0b6955a2009-05-26 19:13:43 -0700118 if (fd < 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100119 ALOGV("socket() failed, throwing");
Nick Pelly0b6955a2009-05-26 19:13:43 -0700120 jniThrowIOException(env, errno);
121 return;
122 }
123
124 auth = env->GetBooleanField(obj, field_mAuth);
125 encrypt = env->GetBooleanField(obj, field_mEncrypt);
126
Nick Pelly6a669fa2009-06-02 15:57:18 -0700127 /* kernel does not yet support LM for SCO */
128 switch (type) {
129 case TYPE_RFCOMM:
130 lm |= auth ? RFCOMM_LM_AUTH : 0;
Nick Pelly1a42cfa2009-09-24 18:03:42 -0700131 lm |= encrypt ? RFCOMM_LM_ENCRYPT : 0;
132 lm |= (auth && encrypt) ? RFCOMM_LM_SECURE : 0;
Nick Pelly6a669fa2009-06-02 15:57:18 -0700133 break;
134 case TYPE_L2CAP:
135 lm |= auth ? L2CAP_LM_AUTH : 0;
Nick Pelly1a42cfa2009-09-24 18:03:42 -0700136 lm |= encrypt ? L2CAP_LM_ENCRYPT : 0;
137 lm |= (auth && encrypt) ? L2CAP_LM_SECURE : 0;
Nick Pelly6a669fa2009-06-02 15:57:18 -0700138 break;
139 }
Nick Pelly0b6955a2009-05-26 19:13:43 -0700140
141 if (lm) {
142 if (setsockopt(fd, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm))) {
Steve Block71f2cf12011-10-20 11:56:00 +0100143 ALOGV("setsockopt(RFCOMM_LM) failed, throwing");
Nick Pelly41a0a4a2009-08-31 13:33:06 -0700144 jniThrowIOException(env, errno);
145 return;
146 }
147 }
148
149 if (type == TYPE_RFCOMM) {
150 sndbuf = RFCOMM_SO_SNDBUF;
151 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
Steve Block71f2cf12011-10-20 11:56:00 +0100152 ALOGV("setsockopt(SO_SNDBUF) failed, throwing");
Nick Pelly0b6955a2009-05-26 19:13:43 -0700153 jniThrowIOException(env, errno);
154 return;
155 }
156 }
157
Steve Block71f2cf12011-10-20 11:56:00 +0100158 ALOGV("...fd %d created (%s, lm = %x)", fd, TYPE_AS_STR(type), lm);
Nick Pelly6a669fa2009-06-02 15:57:18 -0700159
Nick Pelly0b6955a2009-05-26 19:13:43 -0700160 initSocketFromFdNative(env, obj, fd);
161 return;
162#endif
163 jniThrowIOException(env, ENOSYS);
164}
165
Nick Pelly6a669fa2009-06-02 15:57:18 -0700166static void connectNative(JNIEnv *env, jobject obj) {
Nick Pelly0b6955a2009-05-26 19:13:43 -0700167#ifdef HAVE_BLUETOOTH
Steve Block71f2cf12011-10-20 11:56:00 +0100168 ALOGV("%s", __FUNCTION__);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700169
170 int ret;
Nick Pelly6a669fa2009-06-02 15:57:18 -0700171 jint type;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700172 const char *c_address;
Nick Pelly6a669fa2009-06-02 15:57:18 -0700173 jstring address;
174 bdaddr_t bdaddress;
175 socklen_t addr_sz;
176 struct sockaddr *addr;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700177 struct asocket *s = get_socketData(env, obj);
Nick Pellyfbbea2e2011-07-28 17:59:27 -0700178 int retry = 0;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700179
180 if (!s)
181 return;
182
Nick Pelly6a669fa2009-06-02 15:57:18 -0700183 type = env->GetIntField(obj, field_mType);
184
185 /* parse address into bdaddress */
186 address = (jstring) env->GetObjectField(obj, field_mAddress);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700187 c_address = env->GetStringUTFChars(address, NULL);
Nick Pelly6a669fa2009-06-02 15:57:18 -0700188 if (get_bdaddr(c_address, &bdaddress)) {
Nick Pelly0b6955a2009-05-26 19:13:43 -0700189 env->ReleaseStringUTFChars(address, c_address);
190 jniThrowIOException(env, EINVAL);
191 return;
192 }
193 env->ReleaseStringUTFChars(address, c_address);
194
Nick Pelly6a669fa2009-06-02 15:57:18 -0700195 switch (type) {
196 case TYPE_RFCOMM:
197 struct sockaddr_rc addr_rc;
198 addr = (struct sockaddr *)&addr_rc;
199 addr_sz = sizeof(addr_rc);
200
201 memset(addr, 0, addr_sz);
202 addr_rc.rc_family = AF_BLUETOOTH;
203 addr_rc.rc_channel = env->GetIntField(obj, field_mPort);
204 memcpy(&addr_rc.rc_bdaddr, &bdaddress, sizeof(bdaddr_t));
205
206 break;
207 case TYPE_SCO:
208 struct sockaddr_sco addr_sco;
209 addr = (struct sockaddr *)&addr_sco;
210 addr_sz = sizeof(addr_sco);
211
212 memset(addr, 0, addr_sz);
213 addr_sco.sco_family = AF_BLUETOOTH;
214 memcpy(&addr_sco.sco_bdaddr, &bdaddress, sizeof(bdaddr_t));
215
216 break;
217 case TYPE_L2CAP:
218 struct sockaddr_l2 addr_l2;
219 addr = (struct sockaddr *)&addr_l2;
220 addr_sz = sizeof(addr_l2);
221
222 memset(addr, 0, addr_sz);
223 addr_l2.l2_family = AF_BLUETOOTH;
224 addr_l2.l2_psm = env->GetIntField(obj, field_mPort);
225 memcpy(&addr_l2.l2_bdaddr, &bdaddress, sizeof(bdaddr_t));
226
227 break;
228 default:
229 jniThrowIOException(env, ENOSYS);
230 return;
231 }
232
Nick Pellyfbbea2e2011-07-28 17:59:27 -0700233connect:
Nick Pelly6a669fa2009-06-02 15:57:18 -0700234 ret = asocket_connect(s, addr, addr_sz, -1);
Steve Block71f2cf12011-10-20 11:56:00 +0100235 ALOGV("...connect(%d, %s) = %d (errno %d)",
Nick Pelly6a669fa2009-06-02 15:57:18 -0700236 s->fd, TYPE_AS_STR(type), ret, errno);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700237
Nick Pellyfbbea2e2011-07-28 17:59:27 -0700238 if (ret && errno == EALREADY && retry < 2) {
239 /* workaround for bug 5082381 (EALREADY on ACL collision):
240 * retry the connect. Unfortunately we have to create a new fd.
241 * It's not ideal to switch the fd underneath the object, but
242 * is currently safe */
Steve Block5baa3a62011-12-20 16:23:08 +0000243 ALOGD("Hit bug 5082381 (EALREADY on ACL collision), trying workaround");
Nick Pellyfbbea2e2011-07-28 17:59:27 -0700244 usleep(100000);
245 retry++;
246 abortNative(env, obj);
247 destroyNative(env, obj);
248 initSocketNative(env, obj);
249 if (env->ExceptionOccurred()) {
250 return;
251 }
252 goto connect;
253 }
254 if (!ret && retry > 0)
Steve Block5baa3a62011-12-20 16:23:08 +0000255 ALOGD("...workaround ok");
Nick Pellyfbbea2e2011-07-28 17:59:27 -0700256
Nick Pelly0b6955a2009-05-26 19:13:43 -0700257 if (ret)
258 jniThrowIOException(env, errno);
259
260 return;
261#endif
262 jniThrowIOException(env, ENOSYS);
263}
264
Nick Pelly24bb9b82009-10-02 20:34:18 -0700265/* Returns errno instead of throwing, so java can check errno */
266static int bindListenNative(JNIEnv *env, jobject obj) {
Nick Pelly0b6955a2009-05-26 19:13:43 -0700267#ifdef HAVE_BLUETOOTH
Steve Block71f2cf12011-10-20 11:56:00 +0100268 ALOGV("%s", __FUNCTION__);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700269
Nick Pelly6a669fa2009-06-02 15:57:18 -0700270 jint type;
271 socklen_t addr_sz;
272 struct sockaddr *addr;
Doug Kwan75d086e2011-07-16 19:14:18 -0700273 bdaddr_t bdaddr = android_bluetooth_bdaddr_any();
Nick Pelly0b6955a2009-05-26 19:13:43 -0700274 struct asocket *s = get_socketData(env, obj);
275
276 if (!s)
Nick Pelly24bb9b82009-10-02 20:34:18 -0700277 return EINVAL;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700278
Nick Pelly6a669fa2009-06-02 15:57:18 -0700279 type = env->GetIntField(obj, field_mType);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700280
Nick Pelly6a669fa2009-06-02 15:57:18 -0700281 switch (type) {
282 case TYPE_RFCOMM:
283 struct sockaddr_rc addr_rc;
284 addr = (struct sockaddr *)&addr_rc;
285 addr_sz = sizeof(addr_rc);
286
287 memset(addr, 0, addr_sz);
288 addr_rc.rc_family = AF_BLUETOOTH;
289 addr_rc.rc_channel = env->GetIntField(obj, field_mPort);
290 memcpy(&addr_rc.rc_bdaddr, &bdaddr, sizeof(bdaddr_t));
291 break;
292 case TYPE_SCO:
293 struct sockaddr_sco addr_sco;
294 addr = (struct sockaddr *)&addr_sco;
295 addr_sz = sizeof(addr_sco);
296
297 memset(addr, 0, addr_sz);
298 addr_sco.sco_family = AF_BLUETOOTH;
299 memcpy(&addr_sco.sco_bdaddr, &bdaddr, sizeof(bdaddr_t));
300 break;
301 case TYPE_L2CAP:
302 struct sockaddr_l2 addr_l2;
303 addr = (struct sockaddr *)&addr_l2;
304 addr_sz = sizeof(addr_l2);
305
306 memset(addr, 0, addr_sz);
307 addr_l2.l2_family = AF_BLUETOOTH;
308 addr_l2.l2_psm = env->GetIntField(obj, field_mPort);
309 memcpy(&addr_l2.l2_bdaddr, &bdaddr, sizeof(bdaddr_t));
310 break;
311 default:
Nick Pelly24bb9b82009-10-02 20:34:18 -0700312 return ENOSYS;
Nick Pelly6a669fa2009-06-02 15:57:18 -0700313 }
314
315 if (bind(s->fd, addr, addr_sz)) {
Steve Block71f2cf12011-10-20 11:56:00 +0100316 ALOGV("...bind(%d) gave errno %d", s->fd, errno);
Nick Pelly24bb9b82009-10-02 20:34:18 -0700317 return errno;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700318 }
319
320 if (listen(s->fd, 1)) {
Steve Block71f2cf12011-10-20 11:56:00 +0100321 ALOGV("...listen(%d) gave errno %d", s->fd, errno);
Nick Pelly24bb9b82009-10-02 20:34:18 -0700322 return errno;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700323 }
324
Steve Block71f2cf12011-10-20 11:56:00 +0100325 ALOGV("...bindListenNative(%d) success", s->fd);
Nick Pelly41a0a4a2009-08-31 13:33:06 -0700326
Nick Pelly24bb9b82009-10-02 20:34:18 -0700327 return 0;
Nick Pelly41a0a4a2009-08-31 13:33:06 -0700328
Nick Pelly0b6955a2009-05-26 19:13:43 -0700329#endif
Nick Pelly24bb9b82009-10-02 20:34:18 -0700330 return ENOSYS;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700331}
332
333static jobject acceptNative(JNIEnv *env, jobject obj, int timeout) {
334#ifdef HAVE_BLUETOOTH
Steve Block71f2cf12011-10-20 11:56:00 +0100335 ALOGV("%s", __FUNCTION__);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700336
337 int fd;
Nick Pelly6a669fa2009-06-02 15:57:18 -0700338 jint type;
339 struct sockaddr *addr;
340 socklen_t addr_sz;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700341 jstring addr_jstr;
342 char addr_cstr[BTADDR_SIZE];
Nick Pelly6a669fa2009-06-02 15:57:18 -0700343 bdaddr_t *bdaddr;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700344 jboolean auth;
345 jboolean encrypt;
346
347 struct asocket *s = get_socketData(env, obj);
348
349 if (!s)
350 return NULL;
351
Nick Pelly6a669fa2009-06-02 15:57:18 -0700352 type = env->GetIntField(obj, field_mType);
353
354 switch (type) {
355 case TYPE_RFCOMM:
356 struct sockaddr_rc addr_rc;
357 addr = (struct sockaddr *)&addr_rc;
358 addr_sz = sizeof(addr_rc);
359 bdaddr = &addr_rc.rc_bdaddr;
360 memset(addr, 0, addr_sz);
361 break;
362 case TYPE_SCO:
363 struct sockaddr_sco addr_sco;
364 addr = (struct sockaddr *)&addr_sco;
365 addr_sz = sizeof(addr_sco);
366 bdaddr = &addr_sco.sco_bdaddr;
367 memset(addr, 0, addr_sz);
368 break;
369 case TYPE_L2CAP:
370 struct sockaddr_l2 addr_l2;
371 addr = (struct sockaddr *)&addr_l2;
372 addr_sz = sizeof(addr_l2);
373 bdaddr = &addr_l2.l2_bdaddr;
374 memset(addr, 0, addr_sz);
375 break;
376 default:
377 jniThrowIOException(env, ENOSYS);
378 return NULL;
379 }
380
381 fd = asocket_accept(s, addr, &addr_sz, timeout);
382
Steve Block71f2cf12011-10-20 11:56:00 +0100383 ALOGV("...accept(%d, %s) = %d (errno %d)",
Nick Pelly6a669fa2009-06-02 15:57:18 -0700384 s->fd, TYPE_AS_STR(type), fd, errno);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700385
386 if (fd < 0) {
387 jniThrowIOException(env, errno);
388 return NULL;
389 }
390
391 /* Connected - return new BluetoothSocket */
392 auth = env->GetBooleanField(obj, field_mAuth);
393 encrypt = env->GetBooleanField(obj, field_mEncrypt);
Nick Pelly6a669fa2009-06-02 15:57:18 -0700394
395 get_bdaddr_as_string(bdaddr, addr_cstr);
396
Nick Pelly0b6955a2009-05-26 19:13:43 -0700397 addr_jstr = env->NewStringUTF(addr_cstr);
Nick Pelly6a669fa2009-06-02 15:57:18 -0700398 return env->NewObject(class_BluetoothSocket, method_BluetoothSocket_ctor,
399 type, fd, auth, encrypt, addr_jstr, -1);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700400
401#endif
402 jniThrowIOException(env, ENOSYS);
403 return NULL;
404}
405
406static jint availableNative(JNIEnv *env, jobject obj) {
407#ifdef HAVE_BLUETOOTH
Steve Block71f2cf12011-10-20 11:56:00 +0100408 ALOGV("%s", __FUNCTION__);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700409
410 int available;
411 struct asocket *s = get_socketData(env, obj);
412
413 if (!s)
414 return -1;
415
416 if (ioctl(s->fd, FIONREAD, &available) < 0) {
417 jniThrowIOException(env, errno);
418 return -1;
419 }
420
421 return available;
422
423#endif
424 jniThrowIOException(env, ENOSYS);
425 return -1;
426}
427
Nick Pelly47e82de2009-06-01 19:09:37 -0700428static jint readNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
429 jint length) {
Nick Pelly0b6955a2009-05-26 19:13:43 -0700430#ifdef HAVE_BLUETOOTH
Steve Block71f2cf12011-10-20 11:56:00 +0100431 ALOGV("%s", __FUNCTION__);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700432
Nick Pelly47e82de2009-06-01 19:09:37 -0700433 int ret;
434 jbyte *b;
Nick Pelly57a22922009-09-25 14:13:49 -0700435 int sz;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700436 struct asocket *s = get_socketData(env, obj);
437
438 if (!s)
439 return -1;
Nick Pelly57a22922009-09-25 14:13:49 -0700440 if (jb == NULL) {
441 jniThrowIOException(env, EINVAL);
442 return -1;
443 }
444 sz = env->GetArrayLength(jb);
445 if (offset < 0 || length < 0 || offset + length > sz) {
446 jniThrowIOException(env, EINVAL);
447 return -1;
448 }
Nick Pelly0b6955a2009-05-26 19:13:43 -0700449
Nick Pelly47e82de2009-06-01 19:09:37 -0700450 b = env->GetByteArrayElements(jb, NULL);
451 if (b == NULL) {
452 jniThrowIOException(env, EINVAL);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700453 return -1;
454 }
455
Nick Pelly47e82de2009-06-01 19:09:37 -0700456 ret = asocket_read(s, &b[offset], length, -1);
457 if (ret < 0) {
458 jniThrowIOException(env, errno);
459 env->ReleaseByteArrayElements(jb, b, JNI_ABORT);
460 return -1;
461 }
462
463 env->ReleaseByteArrayElements(jb, b, 0);
464 return (jint)ret;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700465
466#endif
467 jniThrowIOException(env, ENOSYS);
468 return -1;
469}
470
Nick Pelly47e82de2009-06-01 19:09:37 -0700471static jint writeNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
472 jint length) {
Nick Pelly0b6955a2009-05-26 19:13:43 -0700473#ifdef HAVE_BLUETOOTH
Steve Block71f2cf12011-10-20 11:56:00 +0100474 ALOGV("%s", __FUNCTION__);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700475
Mike Playle36aa8832010-10-22 13:58:17 +0100476 int ret, total;
Nick Pelly47e82de2009-06-01 19:09:37 -0700477 jbyte *b;
Nick Pelly57a22922009-09-25 14:13:49 -0700478 int sz;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700479 struct asocket *s = get_socketData(env, obj);
480
481 if (!s)
Nick Pelly47e82de2009-06-01 19:09:37 -0700482 return -1;
Nick Pelly57a22922009-09-25 14:13:49 -0700483 if (jb == NULL) {
484 jniThrowIOException(env, EINVAL);
485 return -1;
486 }
487 sz = env->GetArrayLength(jb);
488 if (offset < 0 || length < 0 || offset + length > sz) {
489 jniThrowIOException(env, EINVAL);
490 return -1;
491 }
Nick Pelly0b6955a2009-05-26 19:13:43 -0700492
Nick Pelly47e82de2009-06-01 19:09:37 -0700493 b = env->GetByteArrayElements(jb, NULL);
494 if (b == NULL) {
495 jniThrowIOException(env, EINVAL);
496 return -1;
497 }
498
Mike Playle36aa8832010-10-22 13:58:17 +0100499 total = 0;
500 while (length > 0) {
501 ret = asocket_write(s, &b[offset], length, -1);
502 if (ret < 0) {
503 jniThrowIOException(env, errno);
504 env->ReleaseByteArrayElements(jb, b, JNI_ABORT);
505 return -1;
506 }
507 offset += ret;
508 total += ret;
509 length -= ret;
Nick Pelly47e82de2009-06-01 19:09:37 -0700510 }
Nick Pelly0b6955a2009-05-26 19:13:43 -0700511
Nick Pelly47e82de2009-06-01 19:09:37 -0700512 env->ReleaseByteArrayElements(jb, b, JNI_ABORT); // no need to commit
Mike Playle36aa8832010-10-22 13:58:17 +0100513 return (jint)total;
Nick Pelly47e82de2009-06-01 19:09:37 -0700514
Nick Pelly0b6955a2009-05-26 19:13:43 -0700515#endif
516 jniThrowIOException(env, ENOSYS);
Nick Pelly47e82de2009-06-01 19:09:37 -0700517 return -1;
Nick Pelly0b6955a2009-05-26 19:13:43 -0700518}
519
Nick Pelly71c3c782009-09-02 11:51:35 -0700520static void abortNative(JNIEnv *env, jobject obj) {
Nick Pelly0b6955a2009-05-26 19:13:43 -0700521#ifdef HAVE_BLUETOOTH
Steve Block71f2cf12011-10-20 11:56:00 +0100522 ALOGV("%s", __FUNCTION__);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700523 struct asocket *s = get_socketData(env, obj);
524
525 if (!s)
526 return;
527
528 asocket_abort(s);
Nick Pelly6a669fa2009-06-02 15:57:18 -0700529
Steve Block71f2cf12011-10-20 11:56:00 +0100530 ALOGV("...asocket_abort(%d) complete", s->fd);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700531 return;
532#endif
533 jniThrowIOException(env, ENOSYS);
534}
535
536static void destroyNative(JNIEnv *env, jobject obj) {
537#ifdef HAVE_BLUETOOTH
Steve Block71f2cf12011-10-20 11:56:00 +0100538 ALOGV("%s", __FUNCTION__);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700539 struct asocket *s = get_socketData(env, obj);
Nick Pelly6a669fa2009-06-02 15:57:18 -0700540 int fd = s->fd;
541
Nick Pelly0b6955a2009-05-26 19:13:43 -0700542 if (!s)
543 return;
544
545 asocket_destroy(s);
Nick Pelly6a669fa2009-06-02 15:57:18 -0700546
Steve Block71f2cf12011-10-20 11:56:00 +0100547 ALOGV("...asocket_destroy(%d) complete", fd);
Nick Pelly0b6955a2009-05-26 19:13:43 -0700548 return;
549#endif
550 jniThrowIOException(env, ENOSYS);
551}
552
Nick Pelly24bb9b82009-10-02 20:34:18 -0700553static void throwErrnoNative(JNIEnv *env, jobject obj, jint err) {
554 jniThrowIOException(env, err);
555}
556
Nick Pelly0b6955a2009-05-26 19:13:43 -0700557static JNINativeMethod sMethods[] = {
558 {"initSocketNative", "()V", (void*) initSocketNative},
559 {"initSocketFromFdNative", "(I)V", (void*) initSocketFromFdNative},
Nick Pelly6a669fa2009-06-02 15:57:18 -0700560 {"connectNative", "()V", (void *) connectNative},
Nick Pelly24bb9b82009-10-02 20:34:18 -0700561 {"bindListenNative", "()I", (void *) bindListenNative},
Nick Pelly0b6955a2009-05-26 19:13:43 -0700562 {"acceptNative", "(I)Landroid/bluetooth/BluetoothSocket;", (void *) acceptNative},
563 {"availableNative", "()I", (void *) availableNative},
Nick Pelly47e82de2009-06-01 19:09:37 -0700564 {"readNative", "([BII)I", (void *) readNative},
565 {"writeNative", "([BII)I", (void *) writeNative},
Nick Pelly71c3c782009-09-02 11:51:35 -0700566 {"abortNative", "()V", (void *) abortNative},
Nick Pelly0b6955a2009-05-26 19:13:43 -0700567 {"destroyNative", "()V", (void *) destroyNative},
Nick Pelly24bb9b82009-10-02 20:34:18 -0700568 {"throwErrnoNative", "(I)V", (void *) throwErrnoNative},
Nick Pelly0b6955a2009-05-26 19:13:43 -0700569};
570
571int register_android_bluetooth_BluetoothSocket(JNIEnv *env) {
572 jclass clazz = env->FindClass("android/bluetooth/BluetoothSocket");
573 if (clazz == NULL)
574 return -1;
575 class_BluetoothSocket = (jclass) env->NewGlobalRef(clazz);
Nick Pelly6a669fa2009-06-02 15:57:18 -0700576 field_mType = env->GetFieldID(clazz, "mType", "I");
577 field_mAddress = env->GetFieldID(clazz, "mAddress", "Ljava/lang/String;");
578 field_mPort = env->GetFieldID(clazz, "mPort", "I");
Nick Pelly0b6955a2009-05-26 19:13:43 -0700579 field_mAuth = env->GetFieldID(clazz, "mAuth", "Z");
580 field_mEncrypt = env->GetFieldID(clazz, "mEncrypt", "Z");
581 field_mSocketData = env->GetFieldID(clazz, "mSocketData", "I");
Nick Pelly6a669fa2009-06-02 15:57:18 -0700582 method_BluetoothSocket_ctor = env->GetMethodID(clazz, "<init>", "(IIZZLjava/lang/String;I)V");
Nick Pelly0b6955a2009-05-26 19:13:43 -0700583 return AndroidRuntime::registerNativeMethods(env,
584 "android/bluetooth/BluetoothSocket", sMethods, NELEM(sMethods));
585}
586
587} /* namespace android */
588