Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
ve.bluecove.2.0.3.source-code.OSXStackL2CAPServer.mm Maven / Gradle / Ivy
/**
* BlueCove - Java library for Bluetooth
* Copyright (C) 2007-2008 Vlad Skarzhevskyy
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* @version $Id: OSXStackL2CAPServer.mm 1933 2008-03-24 03:26:10Z skarzhevskyy $
*/
#import "OSXStackL2CAPServer.h"
#define CPP_FILE "OSXStackL2CAPServer.mm"
#define DEFAULT_PSM 0x1001
L2CAPServerController* validL2CAPServerControllerHandle(JNIEnv *env, jlong handle) {
if (stack == NULL) {
throwIOException(env, cSTACK_CLOSED);
return NULL;
}
return (L2CAPServerController*)stack->commPool->getObject(env, handle, 'L');
}
L2CAPServerController::L2CAPServerController() {
l2capPSM = 0;
acceptClientComm = NULL;
l2capPSMDataElement = NULL;
}
L2CAPServerController::~L2CAPServerController() {
}
IOReturn L2CAPServerController::publish() {
// publish the service
IOBluetoothSDPServiceRecordRef serviceRecordRef;
IOReturn status = IOBluetoothAddServiceDict((CFDictionaryRef)sdpEntries, &serviceRecordRef);
if (status != kIOReturnSuccess) {
ndebug(("failed to IOBluetoothAddServiceDict"));
return status;
}
IOBluetoothSDPServiceRecord *serviceRecord = [IOBluetoothSDPServiceRecord withSDPServiceRecordRef:serviceRecordRef];
if (serviceRecord == NULL) {
ndebug(("failed to create IOBluetoothSDPServiceRecord"));
} else {
// get service channel ID & service record handle
status = [serviceRecord getL2CAPPSM:&l2capPSM];
if (status != kIOReturnSuccess) {
ndebug(("failed to getL2CAPPSM [0x%08x]", status));
} else {
createPSMDataElement();
[l2capPSMDataElement setObject:[NSNumber numberWithInt:l2capPSM] forKey:kDataElementValue];
status = [serviceRecord getServiceRecordHandle:&sdpServiceRecordHandle];
}
}
// cleanup
IOBluetoothObjectRelease(serviceRecordRef);
return status;
}
IOReturn L2CAPServerController::updateSDPServiceRecord() {
IOReturn status;
if (sdpServiceRecordHandle != 0) {
status = IOBluetoothRemoveServiceWithRecordHandle(sdpServiceRecordHandle);
sdpServiceRecordHandle = 0;
if (status != kIOReturnSuccess) {
return status;
}
}
IOBluetoothSDPServiceRecordRef serviceRecordRef;
status = IOBluetoothAddServiceDict((CFDictionaryRef)sdpEntries, &serviceRecordRef);
if (status != kIOReturnSuccess) {
ndebug(("failed to IOBluetoothAddServiceDict updated"));
return status;
}
IOBluetoothSDPServiceRecord *serviceRecord = [IOBluetoothSDPServiceRecord withSDPServiceRecordRef:serviceRecordRef];
if (serviceRecord == NULL) {
ndebug(("failed to create IOBluetoothSDPServiceRecord updated"));
} else {
// get service channel ID & service record handle
BluetoothL2CAPPSM newL2capPSM;
status = [serviceRecord getL2CAPPSM:&newL2capPSM];
if (status != kIOReturnSuccess) {
ndebug(("failed to getL2CAPPSM updated [0x%08x]", status));
} else {
if (newL2capPSM != l2capPSM) {
ndebug(("Changed L2CAP PSM %d -> %d", l2capPSM, newL2capPSM));
l2capPSM = newL2capPSM;
}
createPSMDataElement();
[l2capPSMDataElement setObject:[NSNumber numberWithInt:l2capPSM] forKey:kDataElementValue];
status = [serviceRecord getServiceRecordHandle:&sdpServiceRecordHandle];
}
}
// cleanup
IOBluetoothObjectRelease(serviceRecordRef);
return kIOReturnSuccess;
}
void L2CAPServerController::close() {
isClosed = true;
MPSetEvent(incomingChannelNotificationEvent, 0);
if (sdpServiceRecordHandle != 0) {
IOBluetoothRemoveServiceWithRecordHandle(sdpServiceRecordHandle);
sdpServiceRecordHandle = 0;
}
// Unregisters the notification:
if (incomingChannelNotification != NULL) {
IOBluetoothUserNotificationUnregister(incomingChannelNotification);
incomingChannelNotification = NULL;
}
}
void L2CAPServerController::createPSMDataElement() {
if (l2capPSMDataElement != NULL) {
return;
}
NSMutableArray *protocolDescriptorList = [sdpEntries objectForKey:kServiceItemKeyProtocolDescriptorList];
if (protocolDescriptorList == nil) {
ndebug(("create protocolDescriptorList"));
protocolDescriptorList = [NSMutableArray array];
[sdpEntries setObject:protocolDescriptorList forKey:kServiceItemKeyProtocolDescriptorList];
}
NSMutableArray *protocolDescriptorList1 = [protocolDescriptorList objectAtIndex:0];
if (protocolDescriptorList1 == nil) {
ndebug(("create protocolDescriptorList1"));
protocolDescriptorList1 = [NSMutableArray array];
IOBluetoothSDPUUID* l2cap_uuid = [IOBluetoothSDPUUID uuid16:0x0100];
[protocolDescriptorList1 addObject:l2cap_uuid];
[protocolDescriptorList addObject:protocolDescriptorList1];
}
//0x1001-0xFFFF dynamically assigned
int psm = DEFAULT_PSM;
l2capPSMDataElement = [protocolDescriptorList1 objectAtIndex:1];
if (l2capPSMDataElement == nil) {
ndebug(("create l2capPSMDataElement"));
l2capPSMDataElement = createIntDataElement(2, 1, psm);
[protocolDescriptorList1 addObject:l2capPSMDataElement];
}
}
L2CAPServicePublish::L2CAPServicePublish() {
name = "L2CAPServicePublish";
}
void L2CAPServicePublish::run() {
comm->init();
NSString* srvName = [NSString stringWithCharacters:(UniChar*)serviceName length:serviceNameLength];
[comm->sdpEntries setObject:srvName forKey:kServiceItemKeyServiceName];
/*
0x0001 ServiceClassIDList: DATSEQ {
UUID b10c0be1111111111111111111110002 (BlueCoveT L2CAP long)
}
*/
NSMutableArray *currentServiceList = [comm->sdpEntries objectForKey:kServiceItemKeyServiceClassIDList];
if (currentServiceList == nil) {
currentServiceList = [NSMutableArray array];
}
[currentServiceList addObject:[NSData dataWithBytes:uuidValue length:uuidValueLength]];
// update dict
[comm->sdpEntries setObject:currentServiceList forKey:kServiceItemKeyServiceClassIDList];
/*
0x0004 ProtocolDescriptorList: DATSEQ {
DATSEQ {
UUID 0000010000001000800000805f9b34fb (L2CAP)
U_INT_2 0x1001
}
}
*/
bool createProtocolDescriptorList = true;
if (createProtocolDescriptorList) {
NSMutableArray *protocolDescriptorList = [NSMutableArray array];
NSMutableArray *protocolDescriptorList1 = [NSMutableArray array];
[protocolDescriptorList addObject:protocolDescriptorList1];
IOBluetoothSDPUUID* l2cap_uuid = [IOBluetoothSDPUUID uuid16:0x0100];
[protocolDescriptorList1 addObject:l2cap_uuid];
//0x1001-0xFFFF dynamically assigned
int psm = DEFAULT_PSM;
if (assignPsm != 0) {
psm = assignPsm;
}
comm->l2capPSMDataElement = createIntDataElement(2, 1, psm);
[protocolDescriptorList1 addObject:comm->l2capPSMDataElement];
[comm->sdpEntries setObject:protocolDescriptorList forKey:kServiceItemKeyProtocolDescriptorList];
} else {
if (assignPsm != 0) {
comm->createPSMDataElement();
[comm->l2capPSMDataElement setObject:[NSNumber numberWithInt:assignPsm] forKey:kDataElementValue];
}
}
// publish the service
status = comm->publish();
if (status != kIOReturnSuccess) {
error = 1;
}
}
RUNNABLE(L2CAPServiceClose, "L2CAPServiceClose") {
L2CAPServerController* comm = (L2CAPServerController*)pData[0];
comm->close();
}
void L2CAPServiceCloseExec(L2CAPServerController* comm) {
L2CAPServiceClose runnable;
runnable.pData[0] = comm;
synchronousBTOperation(&runnable);
comm->readyToFree = TRUE;
}
JNIEXPORT jlong JNICALL Java_com_intel_bluetooth_BluetoothStackOSX_l2ServerOpenImpl
(JNIEnv *env, jobject, jbyteArray uuidValue, jboolean authenticate, jboolean encrypt, jstring name, jint receiveMTU, jint transmitMTU, jint assignPsm) {
L2CAPServerController* comm = new L2CAPServerController();
if (!stack->commPool->addObject(comm, 'L')) {
delete comm;
throwBluetoothConnectionException(env, BT_CONNECTION_ERROR_NO_RESOURCES, "No free connections Objects in Pool");
return 0;
}
comm->authenticate = authenticate;
L2CAPServicePublish runnable;
runnable.comm = comm;
runnable.uuidValue = env->GetByteArrayElements(uuidValue, 0);
runnable.uuidValueLength = env->GetArrayLength(uuidValue);
runnable.serviceName = env->GetStringChars(name, 0);
runnable.serviceNameLength = env->GetStringLength(name);
runnable.authenticate = authenticate;
runnable.encrypt = encrypt;
comm->receiveMTU = receiveMTU;
comm->transmitMTU = transmitMTU;
runnable.assignPsm = assignPsm;
synchronousBTOperation(&runnable);
env->ReleaseByteArrayElements(uuidValue, runnable.uuidValue, 0);
env->ReleaseStringChars(name, runnable.serviceName);
if (runnable.error != 0) {
L2CAPServiceCloseExec(comm);
throwIOException(env, "Failed to create L2CAP service [0x%08x]", runnable.status);
return 0;
}
debug(("L2CAP server created, PSM %x", comm->l2capPSM));
return comm->internalHandle;
}
JNIEXPORT jint JNICALL Java_com_intel_bluetooth_BluetoothStackOSX_l2ServerPSM
(JNIEnv *env, jobject, jlong handle) {
L2CAPServerController* comm = validL2CAPServerControllerHandle(env, handle);
if (comm == NULL) {
return 0;
}
return comm->l2capPSM;
}
JNIEXPORT void JNICALL Java_com_intel_bluetooth_BluetoothStackOSX_l2ServerCloseImpl
(JNIEnv *env, jobject, jlong handle) {
L2CAPServerController* comm = validL2CAPServerControllerHandle(env, handle);
if (comm == NULL) {
return;
}
L2CAPServiceCloseExec(comm);
}
void l2capServiceOpenNotificationCallback(void *userRefCon, IOBluetoothUserNotificationRef inRef, IOBluetoothObjectRef objectRef ) {
ndebug(("l2capServiceOpenNotificationCallback"));
L2CAPServerController* comm = (L2CAPServerController*)userRefCon;
if (comm == NULL) {
return;
}
if ((comm->magic1 != MAGIC_1) || (comm->magic2 != MAGIC_2)) {
return;
}
IOBluetoothL2CAPChannel *l2capChannel = [IOBluetoothL2CAPChannel withL2CAPChannelRef:(IOBluetoothL2CAPChannelRef)objectRef];
if (l2capChannel == NULL) {
ndebug(("fail to get IOBluetoothL2CAPChannel"));
return;
}
if (comm->authenticate) {
IOBluetoothDevice* device = [l2capChannel getDevice];
if (device == NULL) {
ndebug(("drop incomming connection unable to get device"));
[l2capChannel closeChannel];
return;
}
IOReturn as = [device requestAuthentication];
if (as != kIOReturnSuccess) {
ndebug(("drop incomming connection unable to authenticate [0x%08x]", as));
[l2capChannel closeChannel];
return;
}
ndebug(("L2CAP incomming connection authenticated"));
}
L2CAPChannelController* client = comm->acceptClientComm;
if (client == NULL) {
ndebug(("drop incomming connection since AcceptAndOpen not running"));
return;
}
client->openIncomingChannel(l2capChannel);
comm->openningClient = true;
MPSetEvent(comm->incomingChannelNotificationEvent, 0);
}
RUNNABLE(L2CAPServiceRegisterForOpen, "L2CAPServiceRegisterForOpen") {
L2CAPServerController* comm = (L2CAPServerController*)pData[0];
comm->incomingChannelNotification = IOBluetoothRegisterForFilteredL2CAPChannelOpenNotifications(l2capServiceOpenNotificationCallback, comm, comm->l2capPSM, kIOBluetoothUserNotificationChannelDirectionIncoming);
if (comm->incomingChannelNotification == NULL) {
error = 1;
}
}
JNIEXPORT jlong JNICALL Java_com_intel_bluetooth_BluetoothStackOSX_l2ServerAcceptAndOpenServerConnection
(JNIEnv *env, jobject peer, jlong handle) {
L2CAPServerController* comm = validL2CAPServerControllerHandle(env, handle);
if (comm == NULL) {
return 0;
}
// Avoid more than once Accept at the same time
while ((stack != NULL) && (!comm->isClosed) && (comm->acceptClientComm != NULL)) {
MPEventFlags flags;
OSStatus err = MPWaitForEvent(comm->acceptedEvent, &flags, kDurationMillisecond * 500);
if ((err != kMPTimeoutErr) && (err != noErr)) {
throwRuntimeException(env, "MPWaitForEvent");
return 0;
}
if (isCurrentThreadInterrupted(env, peer)) {
debug(("Interrupted while waiting for connections"));
return 0;
}
}
if (stack == NULL) {
throwIOException(env, cSTACK_CLOSED);
return 0;
}
if (comm->isClosed) {
throwIOException(env, cCONNECTION_IS_CLOSED);
return 0;
}
if (comm->incomingChannelNotification == NULL) {
L2CAPServiceRegisterForOpen runnable;
runnable.pData[0] = comm;
synchronousBTOperation(&runnable);
if (runnable.error) {
throwIOException(env, "Failed to register for L2CAPChannel Notifications");
return 0;
}
}
debug(("create ChannelController to accept incoming connection"));
L2CAPChannelController* clientComm = new L2CAPChannelController();
if (!stack->commPool->addObject(clientComm, 'l')) {
delete clientComm;
throwBluetoothConnectionException(env, BT_CONNECTION_ERROR_NO_RESOURCES, "No free connections Objects in Pool");
return 0;
}
clientComm->receiveMTU = comm->receiveMTU;
clientComm->transmitMTU = comm->transmitMTU;
comm->acceptClientComm = clientComm;
comm->openningClient = false;
BOOL error = false;
while ((stack != NULL) && (!comm->isClosed) && (comm->openningClient == false)) {
MPEventFlags flags;
OSStatus err = MPWaitForEvent(comm->incomingChannelNotificationEvent, &flags, kDurationMillisecond * 500);
if ((err != kMPTimeoutErr) && (err != noErr)) {
throwRuntimeException(env, "MPWaitForEvent");
error = true;
break;
}
if (isCurrentThreadInterrupted(env, peer)) {
debug(("Interrupted while waiting for connections"));
error = true;
break;
}
}
if ((stack != NULL) && (!comm->isClosed)) {
comm->acceptClientComm = NULL;
MPSetEvent(comm->acceptedEvent, 0);
}
if ((error) || (stack == NULL) || (comm->isClosed) || (!comm->openningClient)) {
clientComm->readyToFree = TRUE;
if (!error) {
throwIOException(env, cCONNECTION_IS_CLOSED);
}
return 0;
} else {
int timeout = 120 * 1000;
if (!clientComm->waitForConnection(env, peer, false, timeout)) {
L2CAPChannelCloseExec(clientComm);
return 0;
}
debug(("L2CAP client connected"));
return clientComm->internalHandle;;
}
}