diff options
Diffstat (limited to 'nci/jni/PeerToPeer.cpp')
-rw-r--r-- | nci/jni/PeerToPeer.cpp | 1840 |
1 files changed, 1840 insertions, 0 deletions
diff --git a/nci/jni/PeerToPeer.cpp b/nci/jni/PeerToPeer.cpp new file mode 100644 index 0000000..7994e2a --- /dev/null +++ b/nci/jni/PeerToPeer.cpp @@ -0,0 +1,1840 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Communicate with a peer using NFC-DEP, LLCP, SNEP. + */ +#include "OverrideLog.h" +#include "PeerToPeer.h" +#include "NfcJniUtil.h" +#include "llcp_defs.h" +#include "config.h" +#include "JavaClassConstants.h" + +using namespace android; + +namespace android +{ + extern void nativeNfcTag_registerNdefTypeHandler (); + extern void nativeNfcTag_deregisterNdefTypeHandler (); +} + + +PeerToPeer PeerToPeer::sP2p; +const std::string P2pServer::sSnepServiceName ("urn:nfc:sn:snep"); + + +/******************************************************************************* +** +** Function: PeerToPeer +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +PeerToPeer::PeerToPeer () +: mRemoteWKS (0), + mIsP2pListening (false), + mP2pListenTechMask (NFA_TECHNOLOGY_MASK_A + | NFA_TECHNOLOGY_MASK_F + | NFA_TECHNOLOGY_MASK_A_ACTIVE + | NFA_TECHNOLOGY_MASK_F_ACTIVE), + mNextJniHandle (1) +{ + unsigned long num = 0; + memset (mServers, 0, sizeof(mServers)); + memset (mClients, 0, sizeof(mClients)); +} + + +/******************************************************************************* +** +** Function: ~PeerToPeer +** +** Description: Free all resources. +** +** Returns: None +** +*******************************************************************************/ +PeerToPeer::~PeerToPeer () +{ +} + + +/******************************************************************************* +** +** Function: getInstance +** +** Description: Get the singleton PeerToPeer object. +** +** Returns: Singleton PeerToPeer object. +** +*******************************************************************************/ +PeerToPeer& PeerToPeer::getInstance () +{ + return sP2p; +} + + +/******************************************************************************* +** +** Function: initialize +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::initialize () +{ + ALOGD ("PeerToPeer::initialize"); + unsigned long num = 0; + + if (GetNumValue ("P2P_LISTEN_TECH_MASK", &num, sizeof (num))) + mP2pListenTechMask = num; +} + + +/******************************************************************************* +** +** Function: findServerLocked +** +** Description: Find a PeerToPeer object by connection handle. +** Assumes mMutex is already held +** nfaP2pServerHandle: Connectin handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +sp<P2pServer> PeerToPeer::findServerLocked (tNFA_HANDLE nfaP2pServerHandle) +{ + for (int i = 0; i < sMax; i++) + { + if ( (mServers[i] != NULL) + && (mServers[i]->mNfaP2pServerHandle == nfaP2pServerHandle) ) + { + return (mServers [i]); + } + } + + // If here, not found + return NULL; +} + + +/******************************************************************************* +** +** Function: findServerLocked +** +** Description: Find a PeerToPeer object by connection handle. +** Assumes mMutex is already held +** serviceName: service name. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +sp<P2pServer> PeerToPeer::findServerLocked (tJNI_HANDLE jniHandle) +{ + for (int i = 0; i < sMax; i++) + { + if ( (mServers[i] != NULL) + && (mServers[i]->mJniHandle == jniHandle) ) + { + return (mServers [i]); + } + } + + // If here, not found + return NULL; +} + + +/******************************************************************************* +** +** Function: findServerLocked +** +** Description: Find a PeerToPeer object by service name +** Assumes mMutex is already heldf +** serviceName: service name. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +sp<P2pServer> PeerToPeer::findServerLocked (const char *serviceName) +{ + for (int i = 0; i < sMax; i++) + { + if ( (mServers[i] != NULL) && (mServers[i]->mServiceName.compare(serviceName) == 0) ) + return (mServers [i]); + } + + // If here, not found + return NULL; +} + + +/******************************************************************************* +** +** Function: registerServer +** +** Description: Let a server start listening for peer's connection request. +** jniHandle: Connection handle. +** serviceName: Server's service name. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::registerServer (tJNI_HANDLE jniHandle, const char *serviceName) +{ + static const char fn [] = "PeerToPeer::registerServer"; + ALOGD ("%s: enter; service name: %s JNI handle: %u", fn, serviceName, jniHandle); + tNFA_STATUS stat = NFA_STATUS_OK; + sp<P2pServer> pSrv = NULL; + UINT8 serverSap = NFA_P2P_ANY_SAP; + + mMutex.lock(); + // Check if already registered + if ((pSrv = findServerLocked(serviceName)) != NULL) + { + ALOGD ("%s: service name=%s already registered, handle: 0x%04x", fn, serviceName, pSrv->mNfaP2pServerHandle); + + // Update JNI handle + pSrv->mJniHandle = jniHandle; + mMutex.unlock(); + return (true); + } + + for (int ii = 0; ii < sMax; ii++) + { + if (mServers[ii] == NULL) + { + pSrv = mServers[ii] = new P2pServer(jniHandle, serviceName); + + ALOGD ("%s: added new p2p server index: %d handle: %u name: %s", fn, ii, jniHandle, serviceName); + break; + } + } + mMutex.unlock(); + + if (pSrv == NULL) + { + ALOGE ("%s: service name=%s no free entry", fn, serviceName); + return (false); + } + + if (pSrv->registerWithStack()) { + ALOGD ("%s: got new p2p server h=0x%X", fn, pSrv->mNfaP2pServerHandle); + return (true); + } else { + ALOGE ("%s: invalid server handle", fn); + removeServer (jniHandle); + return (false); + } +} + + +/******************************************************************************* +** +** Function: removeServer +** +** Description: Free resources related to a server. +** jniHandle: Connection handle. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::removeServer (tJNI_HANDLE jniHandle) +{ + static const char fn [] = "PeerToPeer::removeServer"; + + AutoMutex mutex(mMutex); + + for (int i = 0; i < sMax; i++) + { + if ( (mServers[i] != NULL) && (mServers[i]->mJniHandle == jniHandle) ) + { + ALOGD ("%s: server jni_handle: %u; nfa_handle: 0x%04x; name: %s; index=%d", + fn, jniHandle, mServers[i]->mNfaP2pServerHandle, mServers[i]->mServiceName.c_str(), i); + + mServers [i] = NULL; + return; + } + } + ALOGE ("%s: unknown server jni handle: %u", fn, jniHandle); +} + + +/******************************************************************************* +** +** Function: llcpActivatedHandler +** +** Description: Receive LLLCP-activated event from stack. +** nat: JVM-related data. +** activated: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::llcpActivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_ACTIVATED& activated) +{ + static const char fn [] = "PeerToPeer::llcpActivatedHandler"; + ALOGD ("%s: enter", fn); + JNIEnv* e = NULL; + jclass tag_cls = NULL; + jobject tag = NULL; + jmethodID ctor = 0; + jfieldID f = 0; + + //no longer need to receive NDEF message from a tag + android::nativeNfcTag_deregisterNdefTypeHandler (); + + mRemoteWKS = activated.remote_wks; + + nat->vm->AttachCurrentThread (&e, NULL); + if (e == NULL) + { + ALOGE ("%s: jni env is null", fn); + return; + } + + ALOGD ("%s: get object class", fn); + tag_cls = e->GetObjectClass (nat->cached_P2pDevice); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail get p2p device", fn); + goto TheEnd; + } + + ALOGD ("%s: instantiate", fn); + /* New target instance */ + ctor = e->GetMethodID (tag_cls, "<init>", "()V"); + tag = e->NewObject (tag_cls, ctor); + + /* Set P2P Target mode */ + f = e->GetFieldID (tag_cls, "mMode", "I"); + + if (activated.is_initiator == TRUE) + { + ALOGD ("%s: p2p initiator", fn); + e->SetIntField (tag, f, (jint) MODE_P2P_INITIATOR); + } + else + { + ALOGD ("%s: p2p target", fn); + e->SetIntField (tag, f, (jint) MODE_P2P_TARGET); + } + + /* Set tag handle */ + f = e->GetFieldID (tag_cls, "mHandle", "I"); + e->SetIntField (tag, f, (jint) 0x1234); // ?? This handle is not used for anything + + if (nat->tag != NULL) + { + e->DeleteGlobalRef (nat->tag); + } + nat->tag = e->NewGlobalRef (tag); + + ALOGD ("%s: notify nfc service", fn); + + /* Notify manager that new a P2P device was found */ + e->CallVoidMethod (nat->manager, android::gCachedNfcManagerNotifyLlcpLinkActivation, tag); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail notify", fn); + } + + e->DeleteLocalRef (tag); + +TheEnd: + nat->vm->DetachCurrentThread (); + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: llcpDeactivatedHandler +** +** Description: Receive LLLCP-deactivated event from stack. +** nat: JVM-related data. +** deactivated: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::llcpDeactivatedHandler (nfc_jni_native_data* nat, tNFA_LLCP_DEACTIVATED& deactivated) +{ + static const char fn [] = "PeerToPeer::llcpDeactivatedHandler"; + ALOGD ("%s: enter", fn); + JNIEnv* e = NULL; + + nat->vm->AttachCurrentThread (&e, NULL); + if (e == NULL) + { + ALOGE ("%s: jni env is null", fn); + return; + } + + ALOGD ("%s: notify nfc service", fn); + /* Notify manager that the LLCP is lost or deactivated */ + e->CallVoidMethod (nat->manager, android::gCachedNfcManagerNotifyLlcpLinkDeactivated, nat->tag); + if (e->ExceptionCheck()) + { + e->ExceptionClear(); + ALOGE ("%s: fail notify", fn); + } + + nat->vm->DetachCurrentThread (); + + //let the tag-reading code handle NDEF data event + android::nativeNfcTag_registerNdefTypeHandler (); + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: accept +** +** Description: Accept a peer's request to connect. +** serverJniHandle: Server's handle. +** connJniHandle: Connection handle. +** maxInfoUnit: Maximum information unit. +** recvWindow: Receive window size. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::accept (tJNI_HANDLE serverJniHandle, tJNI_HANDLE connJniHandle, int maxInfoUnit, int recvWindow) +{ + static const char fn [] = "PeerToPeer::accept"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + sp<NfaConn> *pConn = NULL; + bool stat = false; + int ii = 0; + sp<P2pServer> pSrv = NULL; + + ALOGD ("%s: enter; server jni handle: %u; conn jni handle: %u; maxInfoUnit: %d; recvWindow: %d", fn, + serverJniHandle, connJniHandle, maxInfoUnit, recvWindow); + + mMutex.lock(); + if ((pSrv = findServerLocked (serverJniHandle)) == NULL) + { + ALOGE ("%s: unknown server jni handle: %u", fn, serverJniHandle); + mMutex.unlock(); + return (false); + } + mMutex.unlock(); + + return pSrv->accept(serverJniHandle, connJniHandle, maxInfoUnit, recvWindow); +} + + +/******************************************************************************* +** +** Function: deregisterServer +** +** Description: Stop a P2pServer from listening for peer. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::deregisterServer (tJNI_HANDLE jniHandle) +{ + static const char fn [] = "PeerToPeer::deregisterServer"; + ALOGD ("%s: enter; JNI handle: %u", fn, jniHandle); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + sp<P2pServer> pSrv = NULL; + + mMutex.lock(); + if ((pSrv = findServerLocked (jniHandle)) == NULL) + { + ALOGE ("%s: unknown service handle: %u", fn, jniHandle); + mMutex.unlock(); + return (false); + } + mMutex.unlock(); + + { + // Server does not call NFA_P2pDisconnect(), so unblock the accept() + SyncEventGuard guard (pSrv->mConnRequestEvent); + pSrv->mConnRequestEvent.notifyOne(); + } + + nfaStat = NFA_P2pDeregister (pSrv->mNfaP2pServerHandle); + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: deregister error=0x%X", fn, nfaStat); + } + + removeServer (jniHandle); + + ALOGD ("%s: exit", fn); + return true; +} + + +/******************************************************************************* +** +** Function: createClient +** +** Description: Create a P2pClient object for a new out-bound connection. +** jniHandle: Connection handle. +** miu: Maximum information unit. +** rw: Receive window size. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::createClient (tJNI_HANDLE jniHandle, UINT16 miu, UINT8 rw) +{ + static const char fn [] = "PeerToPeer::createClient"; + int i = 0; + ALOGD ("%s: enter: jni h: %u miu: %u rw: %u", fn, jniHandle, miu, rw); + + mMutex.lock(); + sp<P2pClient> client = NULL; + for (i = 0; i < sMax; i++) + { + if (mClients[i] == NULL) + { + mClients [i] = client = new P2pClient(); + + mClients [i]->mClientConn->mJniHandle = jniHandle; + mClients [i]->mClientConn->mMaxInfoUnit = miu; + mClients [i]->mClientConn->mRecvWindow = rw; + break; + } + } + mMutex.unlock(); + + if (client == NULL) + { + ALOGE ("%s: fail", fn); + return (false); + } + + ALOGD ("%s: pClient: 0x%p assigned for client jniHandle: %u", fn, client.get(), jniHandle); + + { + SyncEventGuard guard (mClients[i]->mRegisteringEvent); + NFA_P2pRegisterClient (NFA_P2P_DLINK_TYPE, nfaClientCallback); + mClients[i]->mRegisteringEvent.wait(); //wait for NFA_P2P_REG_CLIENT_EVT + } + + if (mClients[i]->mNfaP2pClientHandle != NFA_HANDLE_INVALID) + { + ALOGD ("%s: exit; new client jniHandle: %u NFA Handle: 0x%04x", fn, jniHandle, client->mClientConn->mNfaConnHandle); + return (true); + } + else + { + ALOGE ("%s: FAILED; new client jniHandle: %u NFA Handle: 0x%04x", fn, jniHandle, client->mClientConn->mNfaConnHandle); + removeConn (jniHandle); + return (false); + } +} + + +/******************************************************************************* +** +** Function: removeConn +** +** Description: Free resources related to a connection. +** jniHandle: Connection handle. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::removeConn(tJNI_HANDLE jniHandle) +{ + static const char fn[] = "PeerToPeer::removeConn"; + int ii = 0, jj = 0; + + AutoMutex mutex(mMutex); + // If the connection is a for a client, delete the client itself + for (ii = 0; ii < sMax; ii++) + { + if ((mClients[ii] != NULL) && (mClients[ii]->mClientConn->mJniHandle == jniHandle)) + { + if (mClients[ii]->mNfaP2pClientHandle != NFA_HANDLE_INVALID) + NFA_P2pDeregister (mClients[ii]->mNfaP2pClientHandle); + + mClients[ii] = NULL; + ALOGD ("%s: deleted client handle: %u index: %u", fn, jniHandle, ii); + return; + } + } + + // If the connection is for a server, just delete the connection + for (ii = 0; ii < sMax; ii++) + { + if (mServers[ii] != NULL) + { + if (mServers[ii]->removeServerConnection(jniHandle)) { + return; + } + } + } + + ALOGE ("%s: could not find handle: %u", fn, jniHandle); +} + + +/******************************************************************************* +** +** Function: connectConnOriented +** +** Description: Estabish a connection-oriented connection to a peer. +** jniHandle: Connection handle. +** serviceName: Peer's service name. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::connectConnOriented (tJNI_HANDLE jniHandle, const char* serviceName) +{ + static const char fn [] = "PeerToPeer::connectConnOriented"; + ALOGD ("%s: enter; h: %u service name=%s", fn, jniHandle, serviceName); + bool stat = createDataLinkConn (jniHandle, serviceName, 0); + ALOGD ("%s: exit; h: %u stat: %u", fn, jniHandle, stat); + return stat; +} + + +/******************************************************************************* +** +** Function: connectConnOriented +** +** Description: Estabish a connection-oriented connection to a peer. +** jniHandle: Connection handle. +** destinationSap: Peer's service access point. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::connectConnOriented (tJNI_HANDLE jniHandle, UINT8 destinationSap) +{ + static const char fn [] = "PeerToPeer::connectConnOriented"; + ALOGD ("%s: enter; h: %u dest sap: 0x%X", fn, jniHandle, destinationSap); + bool stat = createDataLinkConn (jniHandle, NULL, destinationSap); + ALOGD ("%s: exit; h: %u stat: %u", fn, jniHandle, stat); + return stat; +} + + +/******************************************************************************* +** +** Function: createDataLinkConn +** +** Description: Estabish a connection-oriented connection to a peer. +** jniHandle: Connection handle. +** serviceName: Peer's service name. +** destinationSap: Peer's service access point. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::createDataLinkConn (tJNI_HANDLE jniHandle, const char* serviceName, UINT8 destinationSap) +{ + static const char fn [] = "PeerToPeer::createDataLinkConn"; + ALOGD ("%s: enter", fn); + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + sp<P2pClient> pClient = NULL; + + if ((pClient = findClient (jniHandle)) == NULL) + { + ALOGE ("%s: can't find client, JNI handle: %u", fn, jniHandle); + return (false); + } + + { + SyncEventGuard guard (pClient->mConnectingEvent); + pClient->mIsConnecting = true; + + if (serviceName) + nfaStat = NFA_P2pConnectByName (pClient->mNfaP2pClientHandle, + const_cast<char*>(serviceName), pClient->mClientConn->mMaxInfoUnit, + pClient->mClientConn->mRecvWindow); + else if (destinationSap) + nfaStat = NFA_P2pConnectBySap (pClient->mNfaP2pClientHandle, destinationSap, + pClient->mClientConn->mMaxInfoUnit, pClient->mClientConn->mRecvWindow); + if (nfaStat == NFA_STATUS_OK) + { + ALOGD ("%s: wait for connected event mConnectingEvent: 0x%p", fn, pClient.get()); + pClient->mConnectingEvent.wait(); + } + } + + if (nfaStat == NFA_STATUS_OK) + { + if (pClient->mClientConn->mNfaConnHandle == NFA_HANDLE_INVALID) + { + removeConn (jniHandle); + nfaStat = NFA_STATUS_FAILED; + } + else + pClient->mIsConnecting = false; + } + else + { + removeConn (jniHandle); + ALOGE ("%s: fail; error=0x%X", fn, nfaStat); + } + + ALOGD ("%s: exit", fn); + return nfaStat == NFA_STATUS_OK; +} + + +/******************************************************************************* +** +** Function: findClient +** +** Description: Find a PeerToPeer object with a client connection handle. +** nfaConnHandle: Connection handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +sp<P2pClient> PeerToPeer::findClient (tNFA_HANDLE nfaConnHandle) +{ + AutoMutex mutex(mMutex); + for (int i = 0; i < sMax; i++) + { + if ((mClients[i] != NULL) && (mClients[i]->mNfaP2pClientHandle == nfaConnHandle)) + return (mClients[i]); + } + return (NULL); +} + + +/******************************************************************************* +** +** Function: findClient +** +** Description: Find a PeerToPeer object with a client connection handle. +** jniHandle: Connection handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +sp<P2pClient> PeerToPeer::findClient (tJNI_HANDLE jniHandle) +{ + AutoMutex mutex(mMutex); + for (int i = 0; i < sMax; i++) + { + if ((mClients[i] != NULL) && (mClients[i]->mClientConn->mJniHandle == jniHandle)) + return (mClients[i]); + } + return (NULL); +} + + +/******************************************************************************* +** +** Function: findClientCon +** +** Description: Find a PeerToPeer object with a client connection handle. +** nfaConnHandle: Connection handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +sp<P2pClient> PeerToPeer::findClientCon (tNFA_HANDLE nfaConnHandle) +{ + AutoMutex mutex(mMutex); + for (int i = 0; i < sMax; i++) + { + if ((mClients[i] != NULL) && (mClients[i]->mClientConn->mNfaConnHandle == nfaConnHandle)) + return (mClients[i]); + } + return (NULL); +} + + +/******************************************************************************* +** +** Function: findConnection +** +** Description: Find a PeerToPeer object with a connection handle. +** nfaConnHandle: Connection handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +sp<NfaConn> PeerToPeer::findConnection (tNFA_HANDLE nfaConnHandle) +{ + int ii = 0, jj = 0; + + AutoMutex mutex(mMutex); + // First, look through all the client control blocks + for (ii = 0; ii < sMax; ii++) + { + if ( (mClients[ii] != NULL) + && (mClients[ii]->mClientConn->mNfaConnHandle == nfaConnHandle) ) { + return mClients[ii]->mClientConn; + } + } + + // Not found yet. Look through all the server control blocks + for (ii = 0; ii < sMax; ii++) + { + if (mServers[ii] != NULL) + { + sp<NfaConn> conn = mServers[ii]->findServerConnection(nfaConnHandle); + if (conn != NULL) { + return conn; + } + } + } + + // Not found... + return NULL; +} + + +/******************************************************************************* +** +** Function: findConnection +** +** Description: Find a PeerToPeer object with a connection handle. +** jniHandle: Connection handle. +** +** Returns: PeerToPeer object. +** +*******************************************************************************/ +sp<NfaConn> PeerToPeer::findConnection (tJNI_HANDLE jniHandle) +{ + int ii = 0, jj = 0; + + AutoMutex mutex(mMutex); + // First, look through all the client control blocks + for (ii = 0; ii < sMax; ii++) + { + if ( (mClients[ii] != NULL) + && (mClients[ii]->mClientConn->mJniHandle == jniHandle) ) { + return mClients[ii]->mClientConn; + } + } + + // Not found yet. Look through all the server control blocks + for (ii = 0; ii < sMax; ii++) + { + if (mServers[ii] != NULL) + { + sp<NfaConn> conn = mServers[ii]->findServerConnection(jniHandle); + if (conn != NULL) { + return conn; + } + } + } + + // Not found... + return NULL; +} + + +/******************************************************************************* +** +** Function: send +** +** Description: Send data to peer. +** jniHandle: Handle of connection. +** buffer: Buffer of data. +** bufferLen: Length of data. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::send (tJNI_HANDLE jniHandle, UINT8 *buffer, UINT16 bufferLen) +{ + static const char fn [] = "PeerToPeer::send"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + sp<NfaConn> pConn = NULL; + + if ((pConn = findConnection (jniHandle)) == NULL) + { + ALOGE ("%s: can't find connection handle: %u", fn, jniHandle); + return (false); + } + + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: send data; jniHandle: %u nfaHandle: 0x%04X", + fn, pConn->mJniHandle, pConn->mNfaConnHandle); + + while (true) + { + SyncEventGuard guard (pConn->mCongEvent); + nfaStat = NFA_P2pSendData (pConn->mNfaConnHandle, bufferLen, buffer); + if (nfaStat == NFA_STATUS_CONGESTED) + pConn->mCongEvent.wait (); //wait for NFA_P2P_CONGEST_EVT + else + break; + + if (pConn->mNfaConnHandle == NFA_HANDLE_INVALID) //peer already disconnected + { + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: peer disconnected", fn); + return (false); + } + } + + if (nfaStat == NFA_STATUS_OK) + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit OK; JNI handle: %u NFA Handle: 0x%04x", fn, jniHandle, pConn->mNfaConnHandle); + else + ALOGE ("%s: Data not sent; JNI handle: %u NFA Handle: 0x%04x error: 0x%04x", + fn, jniHandle, pConn->mNfaConnHandle, nfaStat); + + return nfaStat == NFA_STATUS_OK; +} + + +/******************************************************************************* +** +** Function: receive +** +** Description: Receive data from peer. +** jniHandle: Handle of connection. +** buffer: Buffer to store data. +** bufferLen: Max length of buffer. +** actualLen: Actual length received. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::receive (tJNI_HANDLE jniHandle, UINT8* buffer, UINT16 bufferLen, UINT16& actualLen) +{ + static const char fn [] = "PeerToPeer::receive"; + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; jniHandle: %u bufferLen: %u", fn, jniHandle, bufferLen); + sp<NfaConn> pConn = NULL; + tNFA_STATUS stat = NFA_STATUS_FAILED; + UINT32 actualDataLen2 = 0; + BOOLEAN isMoreData = TRUE; + bool retVal = false; + + if ((pConn = findConnection (jniHandle)) == NULL) + { + ALOGE ("%s: can't find connection handle: %u", fn, jniHandle); + return (false); + } + + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: jniHandle: %u nfaHandle: 0x%04X buf len=%u", fn, pConn->mJniHandle, pConn->mNfaConnHandle, bufferLen); + + while (pConn->mNfaConnHandle != NFA_HANDLE_INVALID) + { + //NFA_P2pReadData() is synchronous + stat = NFA_P2pReadData (pConn->mNfaConnHandle, bufferLen, &actualDataLen2, buffer, &isMoreData); + if ((stat == NFA_STATUS_OK) && (actualDataLen2 > 0)) //received some data + { + actualLen = (UINT16) actualDataLen2; + retVal = true; + break; + } + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: waiting for data...", fn); + { + SyncEventGuard guard (pConn->mReadEvent); + pConn->mReadEvent.wait(); + } + } //while + + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit; nfa h: 0x%X ok: %u actual len: %u", fn, pConn->mNfaConnHandle, retVal, actualLen); + return retVal; +} + + +/******************************************************************************* +** +** Function: disconnectConnOriented +** +** Description: Disconnect a connection-oriented connection with peer. +** jniHandle: Handle of connection. +** +** Returns: True if ok. +** +*******************************************************************************/ +bool PeerToPeer::disconnectConnOriented (tJNI_HANDLE jniHandle) +{ + static const char fn [] = "PeerToPeer::disconnectConnOriented"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + sp<P2pClient> pClient = NULL; + sp<NfaConn> pConn = NULL; + + ALOGD ("%s: enter; jni handle: %u", fn, jniHandle); + + if ((pConn = findConnection(jniHandle)) == NULL) + { + ALOGE ("%s: can't find connection handle: %u", fn, jniHandle); + return (false); + } + + // If this is a client, he may not be connected yet, so unblock him just in case + if ( ((pClient = findClient(jniHandle)) != NULL) && (pClient->mIsConnecting) ) + { + SyncEventGuard guard (pClient->mConnectingEvent); + pClient->mConnectingEvent.notifyOne(); + return (true); + } + + { + SyncEventGuard guard1 (pConn->mCongEvent); + pConn->mCongEvent.notifyOne (); //unblock send() if congested + } + { + SyncEventGuard guard2 (pConn->mReadEvent); + pConn->mReadEvent.notifyOne (); //unblock receive() + } + + if (pConn->mNfaConnHandle != NFA_HANDLE_INVALID) + { + ALOGD ("%s: try disconn nfa h=0x%04X", fn, pConn->mNfaConnHandle); + SyncEventGuard guard (pConn->mDisconnectingEvent); + nfaStat = NFA_P2pDisconnect (pConn->mNfaConnHandle, FALSE); + + if (nfaStat != NFA_STATUS_OK) + ALOGE ("%s: fail p2p disconnect", fn); + else + pConn->mDisconnectingEvent.wait(); + } + + mDisconnectMutex.lock (); + removeConn (jniHandle); + mDisconnectMutex.unlock (); + + ALOGD ("%s: exit; jni handle: %u", fn, jniHandle); + return nfaStat == NFA_STATUS_OK; +} + + +/******************************************************************************* +** +** Function: getRemoteMaxInfoUnit +** +** Description: Get peer's max information unit. +** jniHandle: Handle of the connection. +** +** Returns: Peer's max information unit. +** +*******************************************************************************/ +UINT16 PeerToPeer::getRemoteMaxInfoUnit (tJNI_HANDLE jniHandle) +{ + static const char fn [] = "PeerToPeer::getRemoteMaxInfoUnit"; + sp<NfaConn> pConn = NULL; + + if ((pConn = findConnection(jniHandle)) == NULL) + { + ALOGE ("%s: can't find client jniHandle: %u", fn, jniHandle); + return 0; + } + ALOGD ("%s: jniHandle: %u MIU: %u", fn, jniHandle, pConn->mRemoteMaxInfoUnit); + return (pConn->mRemoteMaxInfoUnit); +} + + +/******************************************************************************* +** +** Function: getRemoteRecvWindow +** +** Description: Get peer's receive window size. +** jniHandle: Handle of the connection. +** +** Returns: Peer's receive window size. +** +*******************************************************************************/ +UINT8 PeerToPeer::getRemoteRecvWindow (tJNI_HANDLE jniHandle) +{ + static const char fn [] = "PeerToPeer::getRemoteRecvWindow"; + ALOGD ("%s: client jni handle: %u", fn, jniHandle); + sp<NfaConn> pConn = NULL; + + if ((pConn = findConnection(jniHandle)) == NULL) + { + ALOGE ("%s: can't find client", fn); + return 0; + } + return pConn->mRemoteRecvWindow; +} + +/******************************************************************************* +** +** Function: setP2pListenMask +** +** Description: Sets the p2p listen technology mask. +** p2pListenMask: the p2p listen mask to be set? +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::setP2pListenMask (tNFA_TECHNOLOGY_MASK p2pListenMask) { + mP2pListenTechMask = p2pListenMask; +} + +/******************************************************************************* +** +** Function: enableP2pListening +** +** Description: Start/stop polling/listening to peer that supports P2P. +** isEnable: Is enable polling/listening? +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::enableP2pListening (bool isEnable) +{ + static const char fn [] = "PeerToPeer::enableP2pListening"; + tNFA_STATUS nfaStat = NFA_STATUS_FAILED; + + ALOGD ("%s: enter isEnable: %u mIsP2pListening: %u", fn, isEnable, mIsP2pListening); + + // If request to enable P2P listening, and we were not already listening + if ( (isEnable == true) && (mIsP2pListening == false) && (mP2pListenTechMask != 0) ) + { + SyncEventGuard guard (mSetTechEvent); + if ((nfaStat = NFA_SetP2pListenTech (mP2pListenTechMask)) == NFA_STATUS_OK) + { + mSetTechEvent.wait (); + mIsP2pListening = true; + } + else + ALOGE ("%s: fail enable listen; error=0x%X", fn, nfaStat); + } + else if ( (isEnable == false) && (mIsP2pListening == true) ) + { + SyncEventGuard guard (mSetTechEvent); + // Request to disable P2P listening, check if it was enabled + if ((nfaStat = NFA_SetP2pListenTech(0)) == NFA_STATUS_OK) + { + mSetTechEvent.wait (); + mIsP2pListening = false; + } + else + ALOGE ("%s: fail disable listen; error=0x%X", fn, nfaStat); + } + ALOGD ("%s: exit; mIsP2pListening: %u", fn, mIsP2pListening); +} + + +/******************************************************************************* +** +** Function: handleNfcOnOff +** +** Description: Handle events related to turning NFC on/off by the user. +** isOn: Is NFC turning on? +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::handleNfcOnOff (bool isOn) +{ + static const char fn [] = "PeerToPeer::handleNfcOnOff"; + ALOGD ("%s: enter; is on=%u", fn, isOn); + tNFA_STATUS stat = NFA_STATUS_FAILED; + + mIsP2pListening = false; // In both cases, P2P will not be listening + + AutoMutex mutex(mMutex); + if (isOn) + { + // Start with no clients or servers + memset (mServers, 0, sizeof(mServers)); + memset (mClients, 0, sizeof(mClients)); + } + else + { + int ii = 0, jj = 0; + + // Disconnect through all the clients + for (ii = 0; ii < sMax; ii++) + { + if (mClients[ii] != NULL) + { + if (mClients[ii]->mClientConn->mNfaConnHandle == NFA_HANDLE_INVALID) + { + SyncEventGuard guard (mClients[ii]->mConnectingEvent); + mClients[ii]->mConnectingEvent.notifyOne(); + } + else + { + mClients[ii]->mClientConn->mNfaConnHandle = NFA_HANDLE_INVALID; + { + SyncEventGuard guard1 (mClients[ii]->mClientConn->mCongEvent); + mClients[ii]->mClientConn->mCongEvent.notifyOne (); //unblock send() + } + { + SyncEventGuard guard2 (mClients[ii]->mClientConn->mReadEvent); + mClients[ii]->mClientConn->mReadEvent.notifyOne (); //unblock receive() + } + } + } + } //loop + + // Now look through all the server control blocks + for (ii = 0; ii < sMax; ii++) + { + if (mServers[ii] != NULL) + { + mServers[ii]->unblockAll(); + } + } //loop + + } + ALOGD ("%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: nfaServerCallback +** +** Description: Receive LLCP-related events from the stack. +** p2pEvent: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::nfaServerCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* eventData) +{ + static const char fn [] = "PeerToPeer::nfaServerCallback"; + sp<P2pServer> pSrv = NULL; + sp<NfaConn> pConn = NULL; + + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=0x%X", fn, p2pEvent); + + switch (p2pEvent) + { + case NFA_P2P_REG_SERVER_EVT: // NFA_P2pRegisterServer() has started to listen + ALOGD ("%s: NFA_P2P_REG_SERVER_EVT; handle: 0x%04x; service sap=0x%02x name: %s", fn, + eventData->reg_server.server_handle, eventData->reg_server.server_sap, eventData->reg_server.service_name); + + sP2p.mMutex.lock(); + pSrv = sP2p.findServerLocked(eventData->reg_server.service_name); + sP2p.mMutex.unlock(); + if (pSrv == NULL) + { + ALOGE ("%s: NFA_P2P_REG_SERVER_EVT for unknown service: %s", fn, eventData->reg_server.service_name); + } + else + { + SyncEventGuard guard (pSrv->mRegServerEvent); + pSrv->mNfaP2pServerHandle = eventData->reg_server.server_handle; + pSrv->mRegServerEvent.notifyOne(); //unblock registerServer() + } + break; + + case NFA_P2P_ACTIVATED_EVT: //remote device has activated + ALOGD ("%s: NFA_P2P_ACTIVATED_EVT; handle: 0x%04x", fn, eventData->activated.handle); + break; + + case NFA_P2P_DEACTIVATED_EVT: + ALOGD ("%s: NFA_P2P_DEACTIVATED_EVT; handle: 0x%04x", fn, eventData->activated.handle); + break; + + case NFA_P2P_CONN_REQ_EVT: + ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; nfa server h=0x%04x; nfa conn h=0x%04x; remote sap=0x%02x", fn, + eventData->conn_req.server_handle, eventData->conn_req.conn_handle, eventData->conn_req.remote_sap); + + sP2p.mMutex.lock(); + pSrv = sP2p.findServerLocked(eventData->conn_req.server_handle); + sP2p.mMutex.unlock(); + if (pSrv == NULL) + { + ALOGE ("%s: NFA_P2P_CONN_REQ_EVT; unknown server h", fn); + return; + } + ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; server jni h=%u", fn, pSrv->mJniHandle); + + // Look for a connection block that is waiting (handle invalid) + if ((pConn = pSrv->findServerConnection((tNFA_HANDLE) NFA_HANDLE_INVALID)) == NULL) + { + ALOGE ("%s: NFA_P2P_CONN_REQ_EVT; server not listening", fn); + } + else + { + SyncEventGuard guard (pSrv->mConnRequestEvent); + pConn->mNfaConnHandle = eventData->conn_req.conn_handle; + pConn->mRemoteMaxInfoUnit = eventData->conn_req.remote_miu; + pConn->mRemoteRecvWindow = eventData->conn_req.remote_rw; + ALOGD ("%s: NFA_P2P_CONN_REQ_EVT; server jni h=%u; conn jni h=%u; notify conn req", fn, pSrv->mJniHandle, pConn->mJniHandle); + pSrv->mConnRequestEvent.notifyOne(); //unblock accept() + } + break; + + case NFA_P2P_CONNECTED_EVT: + ALOGD ("%s: NFA_P2P_CONNECTED_EVT; h=0x%x remote sap=0x%X", fn, + eventData->connected.client_handle, eventData->connected.remote_sap); + break; + + case NFA_P2P_DISC_EVT: + ALOGD ("%s: NFA_P2P_DISC_EVT; h=0x%04x; reason=0x%X", fn, eventData->disc.handle, eventData->disc.reason); + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->disc.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_DISC_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->disc.handle); + } + else + { + sP2p.mDisconnectMutex.lock (); + pConn->mNfaConnHandle = NFA_HANDLE_INVALID; + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard disconn event", fn); + SyncEventGuard guard3 (pConn->mDisconnectingEvent); + pConn->mDisconnectingEvent.notifyOne (); + ALOGD ("%s: NFA_P2P_DISC_EVT; notified disconn event", fn); + } + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard congest event", fn); + SyncEventGuard guard1 (pConn->mCongEvent); + pConn->mCongEvent.notifyOne (); //unblock write (if congested) + ALOGD ("%s: NFA_P2P_DISC_EVT; notified congest event", fn); + } + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard read event", fn); + SyncEventGuard guard2 (pConn->mReadEvent); + pConn->mReadEvent.notifyOne (); //unblock receive() + ALOGD ("%s: NFA_P2P_DISC_EVT; notified read event", fn); + } + sP2p.mDisconnectMutex.unlock (); + } + break; + + case NFA_P2P_DATA_EVT: + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->data.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_DATA_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->data.handle); + } + else + { + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn, + eventData->data.handle, eventData->data.remote_sap); + SyncEventGuard guard (pConn->mReadEvent); + pConn->mReadEvent.notifyOne(); + } + break; + + case NFA_P2P_CONGEST_EVT: + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->congest.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_CONGEST_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->congest.handle); + } + else + { + ALOGD ("%s: NFA_P2P_CONGEST_EVT; nfa handle: 0x%04x congested: %u", fn, + eventData->congest.handle, eventData->congest.is_congested); + if (eventData->congest.is_congested == FALSE) + { + SyncEventGuard guard (pConn->mCongEvent); + pConn->mCongEvent.notifyOne(); + } + } + break; + + default: + ALOGE ("%s: unknown event 0x%X ????", fn, p2pEvent); + break; + } + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: exit", fn); +} + + +/******************************************************************************* +** +** Function: nfaClientCallback +** +** Description: Receive LLCP-related events from the stack. +** p2pEvent: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::nfaClientCallback (tNFA_P2P_EVT p2pEvent, tNFA_P2P_EVT_DATA* eventData) +{ + static const char fn [] = "PeerToPeer::nfaClientCallback"; + sp<NfaConn> pConn = NULL; + sp<P2pClient> pClient = NULL; + + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: enter; event=%u", fn, p2pEvent); + + switch (p2pEvent) + { + case NFA_P2P_REG_CLIENT_EVT: + // Look for a client that is trying to register + if ((pClient = sP2p.findClient ((tNFA_HANDLE)NFA_HANDLE_INVALID)) == NULL) + { + ALOGE ("%s: NFA_P2P_REG_CLIENT_EVT: can't find waiting client", fn); + } + else + { + ALOGD ("%s: NFA_P2P_REG_CLIENT_EVT; Conn Handle: 0x%04x, pClient: 0x%p", fn, eventData->reg_client.client_handle, pClient.get()); + + SyncEventGuard guard (pClient->mRegisteringEvent); + pClient->mNfaP2pClientHandle = eventData->reg_client.client_handle; + pClient->mRegisteringEvent.notifyOne(); + } + break; + + case NFA_P2P_ACTIVATED_EVT: + // Look for a client that is trying to register + if ((pClient = sP2p.findClient (eventData->activated.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_ACTIVATED_EVT: can't find client", fn); + } + else + { + ALOGD ("%s: NFA_P2P_ACTIVATED_EVT; Conn Handle: 0x%04x, pClient: 0x%p", fn, eventData->activated.handle, pClient.get()); + } + break; + + case NFA_P2P_DEACTIVATED_EVT: + ALOGD ("%s: NFA_P2P_DEACTIVATED_EVT: conn handle: 0x%X", fn, eventData->deactivated.handle); + break; + + case NFA_P2P_CONNECTED_EVT: + // Look for the client that is trying to connect + if ((pClient = sP2p.findClient (eventData->connected.client_handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_CONNECTED_EVT: can't find client: 0x%04x", fn, eventData->connected.client_handle); + } + else + { + ALOGD ("%s: NFA_P2P_CONNECTED_EVT; client_handle=0x%04x conn_handle: 0x%04x remote sap=0x%X pClient: 0x%p", fn, + eventData->connected.client_handle, eventData->connected.conn_handle, eventData->connected.remote_sap, pClient.get()); + + SyncEventGuard guard (pClient->mConnectingEvent); + pClient->mClientConn->mNfaConnHandle = eventData->connected.conn_handle; + pClient->mClientConn->mRemoteMaxInfoUnit = eventData->connected.remote_miu; + pClient->mClientConn->mRemoteRecvWindow = eventData->connected.remote_rw; + pClient->mConnectingEvent.notifyOne(); //unblock createDataLinkConn() + } + break; + + case NFA_P2P_DISC_EVT: + ALOGD ("%s: NFA_P2P_DISC_EVT; h=0x%04x; reason=0x%X", fn, eventData->disc.handle, eventData->disc.reason); + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->disc.handle)) == NULL) + { + // If no connection, may be a client that is trying to connect + if ((pClient = sP2p.findClientCon ((tNFA_HANDLE)NFA_HANDLE_INVALID)) == NULL) + { + ALOGE ("%s: NFA_P2P_DISC_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->disc.handle); + return; + } + // Unblock createDataLinkConn() + SyncEventGuard guard (pClient->mConnectingEvent); + pClient->mConnectingEvent.notifyOne(); + } + else + { + sP2p.mDisconnectMutex.lock (); + pConn->mNfaConnHandle = NFA_HANDLE_INVALID; + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard disconn event", fn); + SyncEventGuard guard3 (pConn->mDisconnectingEvent); + pConn->mDisconnectingEvent.notifyOne (); + ALOGD ("%s: NFA_P2P_DISC_EVT; notified disconn event", fn); + } + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard congest event", fn); + SyncEventGuard guard1 (pConn->mCongEvent); + pConn->mCongEvent.notifyOne(); //unblock write (if congested) + ALOGD ("%s: NFA_P2P_DISC_EVT; notified congest event", fn); + } + { + ALOGD ("%s: NFA_P2P_DISC_EVT; try guard read event", fn); + SyncEventGuard guard2 (pConn->mReadEvent); + pConn->mReadEvent.notifyOne(); //unblock receive() + ALOGD ("%s: NFA_P2P_DISC_EVT; notified read event", fn); + } + sP2p.mDisconnectMutex.unlock (); + } + break; + + case NFA_P2P_DATA_EVT: + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->data.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_DATA_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->data.handle); + } + else + { + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_DATA_EVT; h=0x%X; remote sap=0x%X", fn, + eventData->data.handle, eventData->data.remote_sap); + SyncEventGuard guard (pConn->mReadEvent); + pConn->mReadEvent.notifyOne(); + } + break; + + case NFA_P2P_CONGEST_EVT: + // Look for the connection block + if ((pConn = sP2p.findConnection(eventData->congest.handle)) == NULL) + { + ALOGE ("%s: NFA_P2P_CONGEST_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->congest.handle); + } + else + { + ALOGD_IF ((appl_trace_level>=BT_TRACE_LEVEL_DEBUG), "%s: NFA_P2P_CONGEST_EVT; nfa handle: 0x%04x congested: %u", fn, + eventData->congest.handle, eventData->congest.is_congested); + + SyncEventGuard guard (pConn->mCongEvent); + pConn->mCongEvent.notifyOne(); + } + break; + + default: + ALOGE ("%s: unknown event 0x%X ????", fn, p2pEvent); + break; + } +} + + +/******************************************************************************* +** +** Function: connectionEventHandler +** +** Description: Receive events from the stack. +** event: Event code. +** eventData: Event data. +** +** Returns: None +** +*******************************************************************************/ +void PeerToPeer::connectionEventHandler (UINT8 event, tNFA_CONN_EVT_DATA* eventData) +{ + switch (event) + { + case NFA_SET_P2P_LISTEN_TECH_EVT: + { + SyncEventGuard guard (mSetTechEvent); + mSetTechEvent.notifyOne(); //unblock NFA_SetP2pListenTech() + break; + } + } +} + + +/******************************************************************************* +** +** Function: getNextJniHandle +** +** Description: Get a new JNI handle. +** +** Returns: A new JNI handle. +** +*******************************************************************************/ +PeerToPeer::tJNI_HANDLE PeerToPeer::getNewJniHandle () +{ + tJNI_HANDLE newHandle = 0; + + mNewJniHandleMutex.lock (); + newHandle = mNextJniHandle++; + mNewJniHandleMutex.unlock (); + return newHandle; +} + + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + + +/******************************************************************************* +** +** Function: P2pServer +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +P2pServer::P2pServer(PeerToPeer::tJNI_HANDLE jniHandle, const char* serviceName) +: mNfaP2pServerHandle (NFA_HANDLE_INVALID), + mJniHandle (jniHandle) +{ + mServiceName.assign (serviceName); + + memset (mServerConn, 0, sizeof(mServerConn)); +} + +bool P2pServer::registerWithStack() +{ + static const char fn [] = "P2pServer::registerWithStack"; + ALOGD ("%s: enter; service name: %s JNI handle: %u", fn, mServiceName.c_str(), mJniHandle); + tNFA_STATUS stat = NFA_STATUS_OK; + UINT8 serverSap = NFA_P2P_ANY_SAP; + + /********************** + default values for all LLCP parameters: + - Local Link MIU (LLCP_MIU) + - Option parameter (LLCP_OPT_VALUE) + - Response Waiting Time Index (LLCP_WAITING_TIME) + - Local Link Timeout (LLCP_LTO_VALUE) + - Inactivity Timeout as initiator role (LLCP_INIT_INACTIVITY_TIMEOUT) + - Inactivity Timeout as target role (LLCP_TARGET_INACTIVITY_TIMEOUT) + - Delay SYMM response (LLCP_DELAY_RESP_TIME) + - Data link connection timeout (LLCP_DATA_LINK_CONNECTION_TOUT) + - Delay timeout to send first PDU as initiator (LLCP_DELAY_TIME_TO_SEND_FIRST_PDU) + ************************/ + stat = NFA_P2pSetLLCPConfig (LLCP_MAX_MIU, + LLCP_OPT_VALUE, + LLCP_WAITING_TIME, + LLCP_LTO_VALUE, + 0, //use 0 for infinite timeout for symmetry procedure when acting as initiator + 0, //use 0 for infinite timeout for symmetry procedure when acting as target + LLCP_DELAY_RESP_TIME, + LLCP_DATA_LINK_CONNECTION_TOUT, + LLCP_DELAY_TIME_TO_SEND_FIRST_PDU); + if (stat != NFA_STATUS_OK) + ALOGE ("%s: fail set LLCP config; error=0x%X", fn, stat); + + if (sSnepServiceName.compare(mServiceName) == 0) + serverSap = LLCP_SAP_SNEP; //LLCP_SAP_SNEP == 4 + + { + SyncEventGuard guard (mRegServerEvent); + stat = NFA_P2pRegisterServer (serverSap, NFA_P2P_DLINK_TYPE, const_cast<char*>(mServiceName.c_str()), + PeerToPeer::nfaServerCallback); + if (stat != NFA_STATUS_OK) + { + ALOGE ("%s: fail register p2p server; error=0x%X", fn, stat); + return (false); + } + ALOGD ("%s: wait for listen-completion event", fn); + // Wait for NFA_P2P_REG_SERVER_EVT + mRegServerEvent.wait (); + } + + return (mNfaP2pServerHandle != NFA_HANDLE_INVALID); +} + +bool P2pServer::accept(PeerToPeer::tJNI_HANDLE serverJniHandle, PeerToPeer::tJNI_HANDLE connJniHandle, + int maxInfoUnit, int recvWindow) +{ + static const char fn [] = "P2pServer::accept"; + tNFA_STATUS nfaStat = NFA_STATUS_OK; + + sp<NfaConn> connection = allocateConnection(connJniHandle); + if (connection == NULL) { + ALOGE ("%s: failed to allocate new server connection", fn); + return false; + } + + { + // Wait for NFA_P2P_CONN_REQ_EVT or NFA_NDEF_DATA_EVT when remote device requests connection + SyncEventGuard guard (mConnRequestEvent); + ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; wait for incoming connection", fn, + serverJniHandle, connJniHandle); + mConnRequestEvent.wait(); + ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; nfa conn h: 0x%X; got incoming connection", fn, + serverJniHandle, connJniHandle, connection->mNfaConnHandle); + } + + if (connection->mNfaConnHandle == NFA_HANDLE_INVALID) + { + removeServerConnection(connJniHandle); + ALOGD ("%s: no handle assigned", fn); + return (false); + } + + ALOGD ("%s: serverJniHandle: %u; connJniHandle: %u; nfa conn h: 0x%X; try accept", fn, + serverJniHandle, connJniHandle, connection->mNfaConnHandle); + nfaStat = NFA_P2pAcceptConn (connection->mNfaConnHandle, maxInfoUnit, recvWindow); + + if (nfaStat != NFA_STATUS_OK) + { + ALOGE ("%s: fail to accept remote; error=0x%X", fn, nfaStat); + return (false); + } + + ALOGD ("%s: exit; serverJniHandle: %u; connJniHandle: %u; nfa conn h: 0x%X", fn, + serverJniHandle, connJniHandle, connection->mNfaConnHandle); + return (true); +} + +void P2pServer::unblockAll() +{ + AutoMutex mutex(mMutex); + for (int jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if (mServerConn[jj] != NULL) + { + mServerConn[jj]->mNfaConnHandle = NFA_HANDLE_INVALID; + { + SyncEventGuard guard1 (mServerConn[jj]->mCongEvent); + mServerConn[jj]->mCongEvent.notifyOne (); //unblock write (if congested) + } + { + SyncEventGuard guard2 (mServerConn[jj]->mReadEvent); + mServerConn[jj]->mReadEvent.notifyOne (); //unblock receive() + } + } + } +} + +sp<NfaConn> P2pServer::allocateConnection (PeerToPeer::tJNI_HANDLE jniHandle) +{ + AutoMutex mutex(mMutex); + // First, find a free connection block to handle the connection + for (int ii = 0; ii < MAX_NFA_CONNS_PER_SERVER; ii++) + { + if (mServerConn[ii] == NULL) + { + mServerConn[ii] = new NfaConn; + mServerConn[ii]->mJniHandle = jniHandle; + return mServerConn[ii]; + } + } + + return NULL; +} + + +/******************************************************************************* +** +** Function: findServerConnection +** +** Description: Find a P2pServer that has the handle. +** nfaConnHandle: NFA connection handle. +** +** Returns: P2pServer object. +** +*******************************************************************************/ +sp<NfaConn> P2pServer::findServerConnection (tNFA_HANDLE nfaConnHandle) +{ + int jj = 0; + + AutoMutex mutex(mMutex); + for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if ( (mServerConn[jj] != NULL) && (mServerConn[jj]->mNfaConnHandle == nfaConnHandle) ) + return (mServerConn[jj]); + } + + // If here, not found + return (NULL); +} + +/******************************************************************************* +** +** Function: findServerConnection +** +** Description: Find a P2pServer that has the handle. +** nfaConnHandle: NFA connection handle. +** +** Returns: P2pServer object. +** +*******************************************************************************/ +sp<NfaConn> P2pServer::findServerConnection (PeerToPeer::tJNI_HANDLE jniHandle) +{ + int jj = 0; + + AutoMutex mutex(mMutex); + for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if ( (mServerConn[jj] != NULL) && (mServerConn[jj]->mJniHandle == jniHandle) ) + return (mServerConn[jj]); + } + + // If here, not found + return (NULL); +} + +/******************************************************************************* +** +** Function: removeServerConnection +** +** Description: Find a P2pServer that has the handle. +** nfaConnHandle: NFA connection handle. +** +** Returns: P2pServer object. +** +*******************************************************************************/ +bool P2pServer::removeServerConnection (PeerToPeer::tJNI_HANDLE jniHandle) +{ + int jj = 0; + + AutoMutex mutex(mMutex); + for (jj = 0; jj < MAX_NFA_CONNS_PER_SERVER; jj++) + { + if ( (mServerConn[jj] != NULL) && (mServerConn[jj]->mJniHandle == jniHandle) ) { + mServerConn[jj] = NULL; + return true; + } + } + + // If here, not found + return false; +} +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + + +/******************************************************************************* +** +** Function: P2pClient +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +P2pClient::P2pClient () +: mNfaP2pClientHandle (NFA_HANDLE_INVALID), + mIsConnecting (false) +{ + mClientConn = new NfaConn(); +} + + +/******************************************************************************* +** +** Function: ~P2pClient +** +** Description: Free all resources. +** +** Returns: None +** +*******************************************************************************/ +P2pClient::~P2pClient () +{ +} + + +///////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////// + + +/******************************************************************************* +** +** Function: NfaConn +** +** Description: Initialize member variables. +** +** Returns: None +** +*******************************************************************************/ +NfaConn::NfaConn() +: mNfaConnHandle (NFA_HANDLE_INVALID), + mJniHandle (0), + mMaxInfoUnit (0), + mRecvWindow (0), + mRemoteMaxInfoUnit (0), + mRemoteRecvWindow (0) +{ +} + |