void populateServiceRecord(JNIEnv *env, jobject serviceRecord, sdp_record_t* sdpRecord, sdp_list_t* attributeList) {
    jclass serviceRecordImplClass = (*env)->GetObjectClass(env, serviceRecord);
    debug("populateServiceRecord");
    jmethodID populateAttributeValueID = getGetMethodID(env, serviceRecordImplClass, "populateAttributeValue", "(ILjavax/bluetooth/DataElement;)V");
    if (populateAttributeValueID == NULL) {
        return;
    }
    int attrCount = 0;
    for(; attributeList; attributeList = attributeList->next) {
        jint attributeID=*(uint16_t*)attributeList->data;
        sdp_data_t *data = sdp_data_get(sdpRecord, (uint16_t)attributeID);
        if (data) {
            jobject dataElement = createDataElement(env, data);
            if ((*env)->ExceptionCheck(env)) {
                break;
            }
            if (dataElement == NULL) {
                break;
            }
            (*env)->CallVoidMethod(env, serviceRecord, populateAttributeValueID, attributeID, dataElement);
            if ((*env)->ExceptionCheck(env)) {
                 break;
            }
            attrCount ++;
        }
    }
    Edebug("attrCount %i", attrCount);
}
Ejemplo n.º 2
0
JNIEXPORT jint JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZDBus_connectionRfRead
  (JNIEnv* env, jobject peer, jlong handle, jbyteArray b, jint off, jint len ) {
    if (b == NULL) {
        throwRuntimeException(env, "Invalid argument");
        return 0;
    }
    jbyte *bytes = (*env)->GetByteArrayElements(env, b, 0);
    if (bytes == NULL) {
        throwRuntimeException(env, "Invalid argument");
        return 0;
    }
    int done = 0;
    while (done == 0) {
        int flags = MSG_DONTWAIT;
        int count = recv(handle, (char *)(bytes + off + done), len - done, flags);
        if (count < 0) {
            if (errno == EAGAIN) { // Try again for non-blocking operation
                count = 0;
                 Edebug("no data available for read");
            } else if (errno == ECONNRESET) { //104 Connection reset by peer
                debug("Connection closed, Connection reset by peer");
                // See InputStream.read();
                done = -1;
                goto rfReadEnd;
            } else {
                throwIOException(env, "Failed to read. [%d] %s", errno, strerror(errno));
                done = 0;
                goto rfReadEnd;
            }
        } else if (count == 0) {
            debug("Connection closed");
            if (done == 0) {
                // See InputStream.read();
                done = -1;
            }
            goto rfReadEnd;
        }
        done += count;
        if (isCurrentThreadInterrupted(env, peer)) {
            done = 0;
            goto rfReadEnd;
        }
        if (done == 0) {
            // Sleep while not avalable
            bool available = false;
            do {
                struct pollfd fds;
                int timeout = 500; // milliseconds
                memset(&fds, 0, sizeof(fds));
                fds.fd = handle;
                fds.events = POLLIN | POLLHUP | POLLERR;// | POLLRDHUP;
                fds.revents = 0;
                //Edebug("poll: wait");
                int poll_rc = poll(&fds, 1, timeout);
                if (poll_rc > 0) {
                    if (fds.revents & (POLLHUP | POLLERR /* | POLLRDHUP */)) {
                        debug("Stream socket peer closed connection");
                        done = -1;
                        goto rfReadEnd;
                    } else if (fds.revents & POLLNVAL) {
                        // socket closed...
                         done = -1;
                         goto rfReadEnd;
                    } else if (fds.revents & POLLIN) {
                        //Edebug("poll: data to read available");
                        available = true;
                    } else {
                        Edebug("poll: revents %i", fds.revents);
                    }
                } else if (poll_rc == -1) {
                    //Edebug("poll: call error %i", errno);
                    throwIOException(env, "Failed to poll. [%d] %s", errno, strerror(errno));
                    done = 0;
                    goto rfReadEnd;
                } else {
                    //Edebug("poll: call timed out");
                }
                if (isCurrentThreadInterrupted(env, peer)) {
                    done = -1;
                    goto rfReadEnd;
                }
            } while (!available);
        }
    }
rfReadEnd:
    (*env)->ReleaseByteArrayElements(env, b, bytes, 0);
    return done;
}
Ejemplo n.º 3
0
JNIEXPORT jlong JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_l2OpenClientConnectionImpl
  (JNIEnv* env, jobject peer, jlong localDeviceBTAddress, jlong address, jint channel, jboolean authenticate, jboolean encrypt, jint receiveMTU, jint transmitMTU, jint timeout) {
    debug("CONNECT connect, psm %d", channel);

    // allocate socket
    int handle = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
    if (handle < 0) {
        throwIOException(env, "Failed to create socket. [%d] %s", errno, strerror(errno));
        return 0;
    }

    struct sockaddr_l2 localAddr;
    //bind local address
    localAddr.l2_family = AF_BLUETOOTH;
    localAddr.l2_psm = 0;
    //bacpy(&localAddr.l2_bdaddr, BDADDR_ANY);
    longToDeviceAddr(localDeviceBTAddress, &localAddr.l2_bdaddr);

    if (bind(handle, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0) {
        throwIOException(env, "Failed to bind socket. [%d] %s", errno, strerror(errno));
        close(handle);
        return 0;
    }

    // Set link mtu and security options
    struct l2cap_options opt;
    socklen_t opt_len = sizeof(opt);
    memset(&opt, 0, opt_len);
    opt.imtu = receiveMTU;
    opt.omtu = (transmitMTU > 0)?transmitMTU:L2CAP_DEFAULT_MTU;
    opt.flush_to = L2CAP_DEFAULT_FLUSH_TO;
    Edebug("L2CAP set imtu %i, omtu %i", opt.imtu, opt.omtu);

    if (setsockopt(handle, SOL_L2CAP, L2CAP_OPTIONS, &opt, opt_len) < 0) {
        throwIOException(env, "Failed to set L2CAP mtu options. [%d] %s", errno, strerror(errno));
        close(handle);
        return 0;
    }

    if (encrypt || authenticate) {
        int socket_opt = 0;
        socklen_t len = sizeof(socket_opt);
        if (getsockopt(handle, SOL_L2CAP, L2CAP_LM, &socket_opt, &len) < 0) {
            throwIOException(env, "Failed to read L2CAP link mode. [%d] %s", errno, strerror(errno));
            close(handle);
            return 0;
        }
        //if (master) {
        //  socket_opt |= L2CAP_LM_MASTER;
        //}
        if (authenticate) {
            socket_opt |= L2CAP_LM_AUTH;
            Edebug("L2CAP set authenticate");
        }
        if (encrypt) {
            socket_opt |= L2CAP_LM_ENCRYPT;
        }

        if ((socket_opt != 0) && setsockopt(handle, SOL_L2CAP, L2CAP_LM, &socket_opt, sizeof(socket_opt)) < 0) {
            throwIOException(env, "Failed to set L2CAP link mode. [%d] %s", errno, strerror(errno));
            close(handle);
            return 0;
        }
    }


    struct sockaddr_l2 remoteAddr;
    remoteAddr.l2_family = AF_BLUETOOTH;
    longToDeviceAddr(address, &remoteAddr.l2_bdaddr);
    remoteAddr.l2_psm = channel;

    // connect to server
    if (connect(handle, (struct sockaddr*)&remoteAddr, sizeof(remoteAddr)) != 0) {
        throwIOException(env, "Failed to connect. [%d] %s", errno, strerror(errno));
        close(handle);
        return 0;
    }
    debug("L2CAP connected, handle %li", handle);

    struct l2cap_options copt;
    if (!l2Get_options(env, handle, &copt)) {
        close(handle);
        return 0;
    }
    debug("L2CAP imtu %i, omtu %i", copt.imtu, copt.omtu);
    return handle;
}
JNIEXPORT jlong JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_l2ServerOpenImpl
  (JNIEnv* env, jobject peer, jlong localDeviceBTAddress, jboolean authorize, jboolean authenticate, jboolean encrypt, jboolean master, jboolean timeouts, jint backlog, jint receiveMTU, jint transmitMTU) {

    // allocate socket
    int handle = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
    if (handle < 0) {
        throwIOException(env, "Failed to create socket. [%d] %s", errno, strerror(errno));
        return 0;
    }

    struct sockaddr_l2 localAddr;
    //bind local address
    localAddr.l2_family = AF_BLUETOOTH;
    localAddr.l2_psm = 0;
    //bacpy(&localAddr.l2_bdaddr, BDADDR_ANY);
    longToDeviceAddr(localDeviceBTAddress, &localAddr.l2_bdaddr);

    if (bind(handle, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0) {
        throwIOException(env, "Failed to bind socket. [%d] %s", errno, strerror(errno));
        close(handle);
        return 0;
    }

    // Set link mtu and security options
    struct l2cap_options opt;
    socklen_t opt_len = sizeof(opt);
    memset(&opt, 0, opt_len);
    opt.imtu = receiveMTU;
    opt.omtu = (transmitMTU > 0)?transmitMTU:L2CAP_DEFAULT_MTU;
    opt.flush_to = L2CAP_DEFAULT_FLUSH_TO;
    Edebug("L2CAP set imtu %i, omtu %i", opt.imtu, opt.omtu);

    if (setsockopt(handle, SOL_L2CAP, L2CAP_OPTIONS, &opt, opt_len) < 0) {
        throwIOException(env, "Failed to set L2CAP mtu options. [%d] %s", errno, strerror(errno));
        close(handle);
        return 0;
    }

    // Set link security options
    if (encrypt || authenticate || authorize || master) {
		int socket_opt = 0;
		socklen_t len = sizeof(socket_opt);
        if (getsockopt(handle, SOL_L2CAP, L2CAP_LM, &socket_opt, &len) < 0) {
            throwIOException(env, "Failed to read L2CAP server mode. [%d] %s", errno, strerror(errno));
            close(handle);
            return 0;
        }
		if (master) {
			socket_opt |= L2CAP_LM_MASTER;
		}
		if (authenticate) {
			socket_opt |= L2CAP_LM_AUTH;
			debug("L2CAP set authenticate");
		}
		if (encrypt) {
			socket_opt |= L2CAP_LM_ENCRYPT;
		}
		if (authorize) {
			socket_opt |= L2CAP_LM_SECURE;
		}

		if ((socket_opt != 0) && setsockopt(handle, SOL_L2CAP, L2CAP_LM, &socket_opt, sizeof(socket_opt)) < 0) {
			throwIOException(env, "Failed to set L2CAP server mode. [%d] %s", errno, strerror(errno));
            close(handle);
            return 0;
		}
    }

    // put socket into listening mode
    if (listen(handle, backlog) < 0) {
        throwIOException(env, "Failed to listen for L2CAP connections. [%d] %s", errno, strerror(errno));
        close(handle);
        return 0;
    }

    return handle;
}
JNIEXPORT jint JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_runSearchServicesImpl
  (JNIEnv *env, jobject peer, jobject searchServicesThread, jlong localDeviceBTAddress, jobjectArray uuidValues, jlong remoteDeviceAddressLong) {

    // Prepare serviceDiscoveredCallback
    jclass peerClass = (*env)->GetObjectClass(env, peer);
    if (peerClass == NULL) {
        throwRuntimeException(env, "Fail to get Object Class");
        return SERVICE_SEARCH_ERROR;
    }

    jmethodID serviceDiscoveredCallback = getGetMethodID(env, peerClass, "serviceDiscoveredCallback", "(Lcom/intel/bluetooth/SearchServicesThread;JJ)Z");
    if (serviceDiscoveredCallback == NULL) {
        return SERVICE_SEARCH_ERROR;
    }

    sdp_list_t *uuidList = NULL;
    sdp_list_t *rsp_list = NULL;
    sdp_session_t *session = NULL;
    jint rc = SERVICE_SEARCH_ERROR;
    const uint16_t max_rec_num = 256;
    int serviceCount = 0;
    int error;

    // convert uuid set from java array to bluez sdp_list_t
    jsize uuidSetSize = (*env)->GetArrayLength(env, uuidValues);
    jsize i;
    debug("runSearchServicesImpl uuidSetSize %i", uuidSetSize);
    for(i = 0; i < uuidSetSize; i++) {
        jbyteArray byteArray = (jbyteArray)(*env)->GetObjectArrayElement(env, uuidValues, i);
        uuid_t* uuid =  (uuid_t*)malloc(sizeof(uuid_t));
        convertUUIDByteArrayToUUID(env, byteArray, uuid);
        uuidList = sdp_list_append(uuidList, uuid);
    }

    // convert remote device address from jlong to bluez bdaddr_t
    bdaddr_t remoteAddress;
    longToDeviceAddr(remoteDeviceAddressLong, &remoteAddress);

    bdaddr_t localAddr;
    longToDeviceAddr(localDeviceBTAddress, &localAddr);

    // connect to the device to retrieve services
    session = sdp_connect(&localAddr, &remoteAddress, SDP_RETRY_IF_BUSY);

    // if connection is not established throw an exception
    if (session == NULL) {
        rc = SERVICE_SEARCH_DEVICE_NOT_REACHABLE;
        goto searchServicesImplEnd;
    }

    // then ask the device for service record handles
    error = sdp_service_search_req(session, uuidList, max_rec_num, &(rsp_list));
    if (error) {
        debug("sdp_service_search_req error %i", error);
        rc = SERVICE_SEARCH_ERROR;
        goto searchServicesImplEnd;
    }
    Edebug("runSearchServicesImpl session %p %li", session, ptr2jlong(session));

    // Notify java about found services
    sdp_list_t* handle;
    for(handle = rsp_list; handle; handle = handle->next) {
        uint32_t record = *(uint32_t*)handle->data;
        jlong recordHandle = record;
        Edebug("runSearchServicesImpl serviceRecordHandle %li", recordHandle);
        jboolean isTerminated = (*env)->CallBooleanMethod(env, peer, serviceDiscoveredCallback, searchServicesThread, ptr2jlong(session), recordHandle);
        if ((*env)->ExceptionCheck(env)) {
            rc = SERVICE_SEARCH_ERROR;
            goto searchServicesImplEnd;
        } else if (isTerminated) {
            rc = SERVICE_SEARCH_TERMINATED;
            goto searchServicesImplEnd;
        }
        serviceCount ++;
    }
    debug("runSearchServicesImpl found %i", serviceCount);
    rc = SERVICE_SEARCH_COMPLETED;
searchServicesImplEnd:
    sdp_list_free(uuidList, free);
    sdp_list_free(rsp_list, free);
    if (session != NULL) {
        sdp_close(session);
    }
    return rc;
}
jobject createDataElement(JNIEnv *env, sdp_data_t *data) {
    Edebug("createDataElement 0x%x", data->dtd);
    jclass dataElementClass = (*env)->FindClass(env, "javax/bluetooth/DataElement");
    jmethodID constructorID;
    jobject dataElement = NULL;
    switch (data->dtd) {
        case SDP_DATA_NIL:
        {
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(I)V");
            if (constructorID == NULL) {
                break;
            }
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_NULL);
            break;
        }
        case SDP_BOOL:
        {
            jboolean boolean = data->val.uint8;
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(Z)V");
            if (constructorID == NULL) {
                break;
            }
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, boolean);
            break;
        }
        case SDP_UINT8:
        {
            jlong value = (jlong)data->val.uint8;
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(IJ)V");
            if (constructorID == NULL) {
                break;
            }
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_U_INT_1, value);
            break;
        }
        case SDP_UINT16:
        {
            jlong value = (jlong)data->val.uint16;
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(IJ)V");
            if (constructorID == NULL) {
                break;
            }
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_U_INT_2, value);
            break;
        }
        case SDP_UINT32:
        {
            jlong value = (jlong)data->val.uint32;
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(IJ)V");
            if (constructorID == NULL) {
                break;
            }
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_U_INT_4, value);
            break;
        }
        case SDP_INT8:
        {
            jlong value = (jlong)data->val.int8;
            constructorID = getGetMethodID(env, dataElementClass,"<init>","(IJ)V");
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_INT_1, value);
            break;
        }
        case SDP_INT16:
        {
            jlong value = (jlong)data->val.int16;
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(IJ)V");
            if (constructorID == NULL) {
                break;
            }
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_INT_2, value);
            break;
        }
        case SDP_INT32:
        {
            jlong value = (jlong)data->val.int32;
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(IJ)V");
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_INT_4, value);
            break;
        }
        case SDP_INT64:
        {
            jlong value = (jlong)data->val.int64;
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(IJ)V");
            if (constructorID == NULL) {
                break;
            }
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_INT_8, value);
            break;
        }
        case SDP_UINT64:
        {
            Edebug("SDP_UINT64");
            uint64_t value = data->val.uint64;
            jbyte* bytes = (jbyte*)&value;
            reverseArray(bytes, sizeof(value));
            jbyteArray byteArray = (*env)->NewByteArray(env, sizeof(value));
            (*env)->SetByteArrayRegion(env, byteArray, 0, sizeof(value), bytes);
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(ILjava/lang/Object;)V");
            if (constructorID == NULL) {
                break;
            }
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_U_INT_8, byteArray);
            break;
        }
        case SDP_UINT128:
        {
            Edebug("SDP_UINT128");
            uint128_t value = data->val.uint128;
            jbyte* bytes = (jbyte*)&value;
            reverseArray(bytes, sizeof(value));
            jbyteArray byteArray = (*env)->NewByteArray(env, sizeof(value));
            (*env)->SetByteArrayRegion(env, byteArray, 0, sizeof(value), bytes);
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(ILjava/lang/Object;)V");
            if (constructorID == NULL) {
                break;
            }
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_U_INT_16, byteArray);
            break;
        }
        case SDP_INT128:
        {
            Edebug("SDP_INT128");
            uint128_t value = data->val.int128;
            jbyte* bytes = (jbyte*)&value;
            reverseArray(bytes, sizeof(value));
            jbyteArray byteArray = (*env)->NewByteArray(env, sizeof(value));
            (*env)->SetByteArrayRegion(env, byteArray, 0, sizeof(value), bytes);
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(ILjava/lang/Object;)V");
            if (constructorID == NULL) {
                break;
            }
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_INT_16, byteArray);
            break;
        }
        case SDP_URL_STR_UNSPEC:
        case SDP_URL_STR8:
        case SDP_URL_STR16:
        case SDP_URL_STR32:
        {
            Edebug("SDP_URL");
            char* str = data->val.str;
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(ILjava/lang/Object;)V");
            if (constructorID == NULL) {
                break;
            }
            jstring string = (*env)->NewStringUTF(env, str);
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_URL, string);
            break;
        }
        case SDP_TEXT_STR_UNSPEC:
        case SDP_TEXT_STR8:
        case SDP_TEXT_STR16:
        case SDP_TEXT_STR32:
        {
            Edebug("SDP_TEXT");
            char* str = data->val.str;
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(ILjava/lang/Object;)V");
            if (constructorID == NULL) {
                break;
            }
            jstring string = (*env)->NewStringUTF(env, str);
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_STRING, string);
            break;
        }
        case SDP_UUID_UNSPEC:
        case SDP_UUID16:
        case SDP_UUID32:
    case SDP_UUID128:
        {
            Edebug("SDP_UUID");
            jobject javaUUID = createJavaUUID(env, data->val.uuid);
            if (javaUUID == NULL) {
                debug("fail to create UUID");
                break;
            }
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(ILjava/lang/Object;)V");
            if (constructorID == NULL) {
                break;
            }
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_UUID, javaUUID);
            break;
        }
        case SDP_SEQ_UNSPEC:
        case SDP_SEQ8:
        case SDP_SEQ16:
        case SDP_SEQ32:
        {
            Edebug("SDP_SEQ");
            sdp_data_t *newData = data->val.dataseq;
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(I)V");
            if (constructorID == NULL) {
                break;
            }
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_DATSEQ);
            jmethodID addElementID = getGetMethodID(env, dataElementClass, "addElement", "(Ljavax/bluetooth/DataElement;)V");
            for(; newData; newData = newData->next) {
                jobject newDataElement = createDataElement(env, newData);
                if (newDataElement != NULL) {
                    (*env)->CallVoidMethod(env, dataElement, addElementID, newDataElement);
                }
                if ((*env)->ExceptionCheck(env)) {
                    break;
                }
            }
            break;
        }
        case SDP_ALT_UNSPEC:
        case SDP_ALT8:
        case SDP_ALT16:
        case SDP_ALT32:
        {
            Edebug("SDP_ALT");
            sdp_data_t *newData = data->val.dataseq;
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(I)V");
            if (constructorID == NULL) {
                break;
            }
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_DATALT);
            jmethodID addElementID = getGetMethodID(env, dataElementClass, "addElement", "(Ljavax/bluetooth/DataElement;)V");
            for(; newData; newData = newData->next) {
                jobject newDataElement = createDataElement(env, newData);
                if (newDataElement == NULL) {
                    break;
                }
                (*env)->CallVoidMethod(env, dataElement, addElementID, newDataElement);
                if ((*env)->ExceptionCheck(env)) {
                    break;
                }
            }
            break;
        }
        default:
        {
            debug("strange data type 0x%x", data->dtd);
            constructorID = getGetMethodID(env, dataElementClass, "<init>", "(I)V");
            if (constructorID == NULL) {
                break;
            }
            dataElement = (*env)->NewObject(env, dataElementClass, constructorID, DATA_ELEMENT_TYPE_NULL);
            break;
        }
    }
    if (dataElement != NULL) {
        Edebug("dataElement created 0x%x", data->dtd);
    }
    if ((*env)->ExceptionCheck(env)) {
        ndebug("Exception in data element creation 0x%x", data->dtd);
    }
    return dataElement;
}