| /* |
| * 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" |
| #include <ScopedLocalRef.h> |
| |
| /* Some older PN544-based solutions would only send the first SYMM back |
| * (as an initiator) after the full LTO (750ms). But our connect timer |
| * starts immediately, and hence we may timeout if the timer is set to |
| * 1000 ms. Worse, this causes us to immediately connect to the NPP |
| * socket, causing concurrency issues in that stack. Increase the default |
| * timeout to 2000 ms, giving us enough time to complete the first connect. |
| */ |
| #define LLCP_DATA_LINK_TIMEOUT 2000 |
| |
| 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) |
| { |
| 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); |
| sp<P2pServer> pSrv = NULL; |
| |
| 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); |
| |
| //no longer need to receive NDEF message from a tag |
| android::nativeNfcTag_deregisterNdefTypeHandler (); |
| |
| mRemoteWKS = activated.remote_wks; |
| |
| JNIEnv* e = NULL; |
| ScopedAttach attach(nat->vm, &e); |
| if (e == NULL) |
| { |
| ALOGE ("%s: jni env is null", fn); |
| return; |
| } |
| |
| ALOGD ("%s: get object class", fn); |
| ScopedLocalRef<jclass> tag_cls(e, e->GetObjectClass(nat->cached_P2pDevice)); |
| if (e->ExceptionCheck()) { |
| e->ExceptionClear(); |
| ALOGE ("%s: fail get p2p device", fn); |
| return; |
| } |
| |
| ALOGD ("%s: instantiate", fn); |
| /* New target instance */ |
| jmethodID ctor = e->GetMethodID(tag_cls.get(), "<init>", "()V"); |
| ScopedLocalRef<jobject> tag(e, e->NewObject(tag_cls.get(), ctor)); |
| |
| /* Set P2P Target mode */ |
| jfieldID f = e->GetFieldID(tag_cls.get(), "mMode", "I"); |
| |
| if (activated.is_initiator == TRUE) { |
| ALOGD ("%s: p2p initiator", fn); |
| e->SetIntField(tag.get(), f, (jint) MODE_P2P_INITIATOR); |
| } else { |
| ALOGD ("%s: p2p target", fn); |
| e->SetIntField(tag.get(), f, (jint) MODE_P2P_TARGET); |
| } |
| |
| /* Set tag handle */ |
| f = e->GetFieldID(tag_cls.get(), "mHandle", "I"); |
| e->SetIntField(tag.get(), f, (jint) 0x1234); // ?? This handle is not used for anything |
| |
| if (nat->tag != NULL) { |
| e->DeleteGlobalRef(nat->tag); |
| } |
| nat->tag = e->NewGlobalRef(tag.get()); |
| |
| ALOGD ("%s: notify nfc service", fn); |
| |
| /* Notify manager that new a P2P device was found */ |
| e->CallVoidMethod(nat->manager, android::gCachedNfcManagerNotifyLlcpLinkActivation, tag.get()); |
| if (e->ExceptionCheck()) { |
| e->ExceptionClear(); |
| ALOGE ("%s: fail notify", fn); |
| } |
| |
| 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; |
| ScopedAttach attach(nat->vm, &e); |
| 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); |
| } |
| |
| //let the tag-reading code handle NDEF data event |
| android::nativeNfcTag_registerNdefTypeHandler (); |
| ALOGD ("%s: exit", fn); |
| } |
| |
| void PeerToPeer::llcpFirstPacketHandler (nfc_jni_native_data* nat) |
| { |
| static const char fn [] = "PeerToPeer::llcpFirstPacketHandler"; |
| ALOGD ("%s: enter", fn); |
| |
| JNIEnv* e = NULL; |
| ScopedAttach attach(nat->vm, &e); |
| 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::gCachedNfcManagerNotifyLlcpFirstPacketReceived, nat->tag); |
| if (e->ExceptionCheck()) |
| { |
| e->ExceptionClear(); |
| ALOGE ("%s: fail notify", fn); |
| } |
| |
| 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"; |
| 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"; |
| |
| AutoMutex mutex(mMutex); |
| // If the connection is a for a client, delete the client itself |
| for (size_t 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 (size_t 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) |
| { |
| AutoMutex mutex(mMutex); |
| // First, look through all the client control blocks |
| for (size_t 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 (size_t 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) |
| { |
| AutoMutex mutex(mMutex); |
| // First, look through all the client control blocks |
| for (size_t 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 (size_t 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); |
| |
| 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 |
| { |
| // Disconnect through all the clients |
| for (size_t 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 (size_t 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.findClient (eventData->disc.handle)) == NULL) |
| { |
| ALOGE ("%s: NFA_P2P_DISC_EVT: can't find client 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_TIMEOUT, |
| 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) |
| { |
| } |