JNIEXPORT void JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZDBus_connectionRfWrite__J_3BII
  (JNIEnv* env, jobject peer, jlong handle, jbyteArray b, jint off, jint len) {
    if (b == NULL) {
        throwRuntimeException(env, "Invalid argument");
        return;
    }
    jbyte *bytes = (*env)->GetByteArrayElements(env, b, 0);
    if (bytes == NULL) {
        throwRuntimeException(env, "Invalid argument");
        return;
    }
    int done = 0;
    while(done < len) {
        int count = send(handle, (char *)(bytes + off + done), len - done, 0);
        if (count < 0) {
            throwIOException(env, "Failed to write. [%d] %s", errno, strerror(errno));
            break;
        }
        if (isCurrentThreadInterrupted(env, peer)) {
            break;
        }
        done += count;
    }
    (*env)->ReleaseByteArrayElements(env, b, bytes, 0);
}
JNIEXPORT jlong JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_l2ServerAcceptAndOpenServerConnection
(JNIEnv* env, jobject peer, jlong handle) {
    struct sockaddr_l2 remoteAddr;
    socklen_t  remoteAddrLen = sizeof(remoteAddr);
    int client_socket = SOCKET_ERROR;
    do {
        client_socket = accept(handle, (struct sockaddr*)&remoteAddr, &remoteAddrLen);
        if (SOCKET_ERROR == client_socket) {
            if (errno == EWOULDBLOCK) {
                if (isCurrentThreadInterrupted(env, peer)) {
                    return 0;
                }
                if (!threadSleep(env, 100)) {
                    return 0;
                }
                continue;
            } else {
                throwIOException(env, "Failed to accept L2CAP client connection. [%d] %s", errno, strerror(errno));
                return 0;
            }
        }
    } while (SOCKET_ERROR == client_socket);
    return client_socket;
}
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;
}
JNIEXPORT jint JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_l2Receive
  (JNIEnv* env, jobject peer, jlong handle, jbyteArray inBuf) {
#ifdef BLUECOVE_L2CAP_MTU_TRUNCATE
    struct l2cap_options opt;
    if (!l2Get_options(env, handle, &opt)) {
       return 0;
    }
#endif //BLUECOVE_L2CAP_MTU_TRUNCATE

    bool dataReady = false;
    while(!dataReady) {
        struct pollfd fds;
        int timeout = 10; // milliseconds
        fds.fd = handle;
        fds.events = POLLIN | POLLHUP | POLLERR;// | POLLRDHUP;
        fds.revents = 0;
        if (poll(&fds, 1, timeout) > 0) {
            if (fds.revents & (POLLHUP | POLLERR /*| POLLRDHUP*/)) {
                throwIOException(env, "Peer closed connection");
                return 0;
            } else if (fds.revents & POLLIN) {
                dataReady = true;
            }
        }
        if(isCurrentThreadInterrupted(env, peer)) {
            return 0;
        }
    }

    jbyte *bytes = (*env)->GetByteArrayElements(env, inBuf, 0);
    size_t inBufLen = (size_t)(*env)->GetArrayLength(env, inBuf);
    int readLen = inBufLen;

#ifdef BLUECOVE_L2CAP_MTU_TRUNCATE
    if (readLen > opt.imtu) {
        readLen = opt.imtu;
    }
#endif //BLUECOVE_L2CAP_MTU_TRUNCATE

#ifdef BLUECOVE_L2CAP_USE_MSG
    int flags = 0;
    iovec iov;
    msghdr msg;
    memset((void*)&iov, 0, sizeof(iov));
    memset((void*)&msg, 0, sizeof(msg));
    iov.iov_base = bytes;
    iov.iov_len = readLen;
    msg.msg_iov = &iov;
    msg.msg_iovlen = 1;

    int count = recvmsg(handle, &msg, flags);
#else
    int count = recv(handle, (char *)bytes, readLen, 0);
#endif //BLUECOVE_L2CAP_USE_MSG
    if (count < 0) {
        throwIOException(env, "Failed to read. [%d] %s", errno, strerror(errno));
        count = 0;
    }

    (*env)->ReleaseByteArrayElements(env, inBuf, bytes, 0);
    debug("receive[] returns %i", count);
    return count;
}
JNIEXPORT jint JNICALL Java_com_intel_bluetooth_BluetoothStackWIDCOMM_l2Receive
(JNIEnv *env, jobject peer, jlong handle, jbyteArray inBuf) {
    WIDCOMMStackL2CapConn* l2c = validL2CapConnHandle(env, handle);
    if (l2c == NULL) {
        return 0;
    }
    debug(("l2(%i) receive(byte[])", l2c->internalHandle));
    if ((!l2c->isConnected ) && (l2c->receiveBuffer.available() < sizeof(UINT16))) {
        throwIOException(env, cCONNECTION_IS_CLOSED);
        return 0;
    }
    if (l2c->receiveBuffer.isOverflown()) {
        throwIOException(env, "Receive buffer overflown");
        return 0;
    }

    HANDLE hEvents[2];
    hEvents[0] = l2c->hConnectionEvent;
    hEvents[1] = l2c->hDataReceivedEvent;

    int paketLengthSize = l2c->receiveBuffer.sizeof_len();

    while ((stack != NULL) && l2c->isConnected  && (l2c->receiveBuffer.available() <= paketLengthSize)) {
        debug(("receive[] waits for data"));
        DWORD  rc = WaitForMultipleObjects(2, hEvents, FALSE, 500);
        if (rc == WAIT_FAILED) {
            throwRuntimeException(env, "WaitForMultipleObjects");
            return 0;
        }
        debug(("receive[] waits returns %s", waitResultsString(rc)));
        if (isCurrentThreadInterrupted(env, peer, "receive")) {
            return 0;
        }
    }
    if ((stack == NULL) || ((!l2c->isConnected) && (l2c->receiveBuffer.available() <= paketLengthSize)) ) {
        throwIOException(env, cCONNECTION_CLOSED);
        return 0;
    }

    int count = l2c->receiveBuffer.available();
    if (count < paketLengthSize) {
        throwIOException(env, "Receive buffer corrupted (1)");
        return 0;
    }
    int paketLength = 0;
    int done = l2c->receiveBuffer.read_len(&paketLength);
    if ((done != paketLengthSize) || (paketLength > (count - paketLengthSize))) {
        throwIOException(env, "Receive buffer corrupted (2)");
        return 0;
    }
    if (paketLength == 0) {
        return 0;
    }

    jbyte *bytes = env->GetByteArrayElements(inBuf, 0);
    UINT16 inBufLen = (UINT16)env->GetArrayLength(inBuf);

    int readLen = paketLength;
    if (readLen > inBufLen) {
        readLen = inBufLen;
    }
    if (readLen > l2c->receiveMTU) {
        readLen = l2c->receiveMTU;
    }

    done = l2c->receiveBuffer.read(bytes, readLen);
    if (done != readLen) {
        throwIOException(env, "Receive buffer corrupted (3)");
    }
    if (done < paketLength) {
        // the rest will be discarded.
        int skip = paketLength - done;
        if (skip != l2c->receiveBuffer.skip(skip)) {
            throwIOException(env, "Receive buffer corrupted (4)");
        }
    }

    env->ReleaseByteArrayElements(inBuf, bytes, 0);
    debug(("receive[] returns %i", done));
    return done;
}
JNIEXPORT jlong JNICALL Java_com_intel_bluetooth_BluetoothStackWIDCOMM_l2ServerAcceptAndOpenServerConnection
(JNIEnv *env, jobject peer, jlong handle) {
    WIDCOMMStackL2CapServer* srv = validL2CapServerHandle(env, handle);
    if (srv == NULL) {
        return 0;
    }
    if (srv->sdpService == NULL) {
        throwIOException(env, cCONNECTION_CLOSED);
        return 0;
    }
    if (!srv->finalizeSDPRecord(env)) {
        return 0;
    }
    #ifdef BWT_SINCE_SDK_6_0_1
    srv->sdpService->CommitRecord();
    #endif

    EnterCriticalSection(&stack->csCommIf);
    if (stack == NULL) {
        throwInterruptedIOException(env, cSTACK_CLOSED);
    }

    WIDCOMMStackL2CapConn* l2c = stack->createL2CapConn();
    if (l2c == NULL) {
        throwBluetoothConnectionException(env, BT_CONNECTION_ERROR_NO_RESOURCES, "No free connections Objects in Pool");
        LeaveCriticalSection(&stack->csCommIf);
        return 0;
    }
    srv->addClient(l2c);
    l2c->receiveMTU = srv->receiveMTU;
    l2c->transmitMTU = srv->transmitMTU;

    BOOL rc = l2c->Listen(&(srv->l2CapIf));
    if (stack != NULL) {
        LeaveCriticalSection(&stack->csCommIf);
    }

    if (!rc) {
        throwBluetoothConnectionException(env, BT_CONNECTION_ERROR_FAILED_NOINFO, "Failed to Listen");
        accept_l2_server_return 0;
    }

    HANDLE hEvents[2];
    hEvents[0] = l2c->hConnectionEvent;
    hEvents[1] = srv->hConnectionEvent;

    debug(("l2s(%i) l2(%i) L2CAP server waits for connection", srv->internalHandle, l2c->internalHandle));
    long incomingConnectionCountWas = incomingL2CAPConnectionCount;
    while ((stack != NULL) && (!srv->isClosing)  && (!l2c->isConnected) && (!l2c->isDisconnected) && (srv->sdpService != NULL)) {
        DWORD  rc = WaitForMultipleObjects(2, hEvents, FALSE, 500);
        if (rc == WAIT_FAILED) {
            throwRuntimeException(env, "WaitForSingleObject");
            accept_l2_server_return 0;
        }
        if ((stack != NULL) && (incomingConnectionCountWas != incomingL2CAPConnectionCount)) {
            debug(("L2CAP server incomingConnectionCount %i", incomingL2CAPConnectionCount));
            incomingConnectionCountWas = incomingL2CAPConnectionCount;
        }
        if (isCurrentThreadInterrupted(env, peer, "accept")) {
            accept_l2_server_return 0;
        }
    }
    if (stack == NULL) {
        throwInterruptedIOException(env, cSTACK_CLOSED);
        return 0;
    }
    if (!l2c->isConnected) {
        if (srv->isClosing || (srv->sdpService == NULL)) {
            throwInterruptedIOException(env, cCONNECTION_CLOSED);
        } else if (l2c->isDisconnected) {
            throwIOException(env, "Connection error");
        } else {
            throwIOException(env, "Failed to connect");
        }
        accept_l2_server_return 0;
    }

    debug(("l2s(%i) l2(%i) L2CAP server connection made", srv->internalHandle, l2c->internalHandle));
    l2c->selectConnectionTransmitMTU(env);
    return l2c->internalHandle;
}
JNIEXPORT jlong JNICALL Java_com_intel_bluetooth_BluetoothStackWIDCOMM_l2OpenClientConnectionImpl
(JNIEnv *env, jobject peer, jlong address, jint channel, jboolean authenticate, jboolean encrypt, jint receiveMTU, jint transmitMTU, jint timeout) {
    BD_ADDR bda;
    LongToBcAddr(address, bda);

    WIDCOMMStackL2CapConn* l2c = NULL;
    EnterCriticalSection(&stack->csCommIf);
    //vc6 __try {
        l2c = stack->createL2CapConn();
        if (l2c == NULL) {
            throwBluetoothConnectionException(env, BT_CONNECTION_ERROR_NO_RESOURCES, "No free connections Objects in Pool");
            open_l2client_return 0;
        }
        debug(("l2(%i) L2CapConn handle created", l2c->internalHandle));
        if ((l2c->hConnectionEvent == NULL) || (l2c->hDataReceivedEvent == NULL)) {
            throwRuntimeException(env, "fails to CreateEvent");
            open_l2client_return 0;
        }
        debug(("L2CapConn channel 0x%X", channel));
        //debug(("AssignPsmValue");

        CL2CapIf *l2CapIf = new CL2CapIf();
        l2c->pL2CapIf = l2CapIf;

        if (!l2CapIf->AssignPsmValue(&(l2c->service_guid), (UINT16)channel)) {
            // What GUID do we need in call to CL2CapIf.AssignPsmValue() if we don't have any?
            // NEED This for stack version 3.0.1.905
            // TODO test on  v5.0.1.2800 and v4.0.1.2900
            GUID any_client_service_guid = {2970356705 , 4369, 4369, {17 , 17, 17 , 17, 17, 17 , 0, 1}};
            memcpy(&(l2c->service_guid), &any_client_service_guid, sizeof(GUID));

            if (!l2CapIf->AssignPsmValue(&(l2c->service_guid), (UINT16)channel)) {
                throwBluetoothConnectionException(env, BT_CONNECTION_ERROR_UNKNOWN_PSM, "failed to assign PSM 0x%X", (UINT16)channel);
                open_l2client_return 0;
            }
        }
        l2CapIf->Register();

        UINT8 sec_level = BTM_SEC_NONE;
        if (authenticate) {
            sec_level = BTM_SEC_OUT_AUTHENTICATE;
        }
        if (encrypt) {
            sec_level = sec_level | BTM_SEC_OUT_ENCRYPT;
        }

        BT_CHAR *p_service_name;
        #ifdef _WIN32_WCE
            p_service_name = (BT_CHAR*)L"bluecovesrv";
        #else // _WIN32_WCE
            p_service_name = "bluecovesrv";
        #endif // #else // _WIN32_WCE

        if (!l2CapIf->SetSecurityLevel(p_service_name, sec_level, FALSE)) {
            throwBluetoothConnectionException(env, BT_CONNECTION_ERROR_SECURITY_BLOCK, "Error setting security level");
            open_l2client_return 0;
        }

        //debug(("OpenL2CAPClient"));
        l2c->transmitMTU = (UINT16)transmitMTU;
        l2c->receiveMTU = (UINT16)receiveMTU;
        BOOL rc = l2c->Connect(l2CapIf, bda, l2c->receiveMTU);
        if (!rc) {
            throwBluetoothConnectionException(env, BT_CONNECTION_ERROR_FAILED_NOINFO, "Failed to Connect");
            open_l2client_return 0;
        }

        //debug(("waitFor Connection signal");
        DWORD waitStart = GetTickCount();
        while ((stack != NULL) && (!l2c->isConnected) && (!l2c->isDisconnected)) {
            DWORD  rc = WaitForSingleObject(l2c->hConnectionEvent, 500);
            if (rc == WAIT_FAILED) {
                throwRuntimeException(env, "WaitForSingleObject");
                open_l2client_return 0;
            }
            if (isCurrentThreadInterrupted(env, peer, "connect")) {
                open_l2client_return 0;
            }
            if ((timeout > 0) && ((GetTickCount() - waitStart)  > (DWORD)timeout)) {
                throwBluetoothConnectionException(env, BT_CONNECTION_ERROR_TIMEOUT, "Connection timeout");
                open_l2client_return 0;
            }
        }
        if (stack == NULL) {
            throwBluetoothConnectionException(env, BT_CONNECTION_ERROR_FAILED_NOINFO, "Failed to connect");
            open_l2client_return 0;
        }
        if (!l2c->isConnected) {
            throwBluetoothConnectionException(env, BT_CONNECTION_ERROR_FAILED_NOINFO, "Failed to connect");
            open_l2client_return 0;
        }

        debug(("l2(%i) l2Client connected", l2c->internalHandle));
        l2c->selectConnectionTransmitMTU(env);
        jlong handle = l2c->internalHandle;
        l2c = NULL;
        open_l2client_return handle;
    /* vc6 } __finally {} */
}