/* * 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 "PeerToPeer.h" #include <android-base/stringprintf.h> #include <base/logging.h> #include <nativehelper/ScopedLocalRef.h> #include "JavaClassConstants.h" #include "NfcJniUtil.h" #include "llcp_defs.h" #include "nfc_config.h" using android::base::StringPrintf; /* 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(); extern void startRfDiscovery(bool isStart); extern bool isDiscoveryStarted(); } // namespace android PeerToPeer PeerToPeer::sP2p; const std::string P2pServer::sSnepServiceName("urn:nfc:sn:snep"); extern bool nfc_debug_enabled; /******************************************************************************* ** ** 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() { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("PeerToPeer::initialize"); if (NfcConfig::hasKey(NAME_P2P_LISTEN_TECH_MASK)) mP2pListenTechMask = NfcConfig::getUnsigned(NAME_P2P_LISTEN_TECH_MASK); } /******************************************************************************* ** ** 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"; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: added new p2p server index: %d handle: %u name: %s", fn, ii, jniHandle, serviceName); break; } } mMutex.unlock(); if (pSrv == NULL) { LOG(ERROR) << StringPrintf("%s: service name=%s no free entry", fn, serviceName); return (false); } if (pSrv->registerWithStack()) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: got new p2p server h=0x%X", fn, pSrv->mNfaP2pServerHandle); return (true); } else { LOG(ERROR) << StringPrintf("%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)) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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; } } LOG(ERROR) << StringPrintf("%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"; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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) { LOG(ERROR) << StringPrintf("%s: jni env is null", fn); return; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: get object class", fn); ScopedLocalRef<jclass> tag_cls(e, e->GetObjectClass(nat->cached_P2pDevice)); if (e->ExceptionCheck()) { e->ExceptionClear(); LOG(ERROR) << StringPrintf("%s: fail get p2p device", fn); return; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: p2p initiator", fn); e->SetIntField(tag.get(), f, (jint)MODE_P2P_INITIATOR); } else { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: p2p target", fn); e->SetIntField(tag.get(), f, (jint)MODE_P2P_TARGET); } /* Set LLCP version */ f = e->GetFieldID(tag_cls.get(), "mLlcpVersion", "B"); e->SetByteField(tag.get(), f, (jbyte)activated.remote_version); /* 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()); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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(); LOG(ERROR) << StringPrintf("%s: fail notify", fn); } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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"; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", fn); JNIEnv* e = NULL; ScopedAttach attach(nat->vm, &e); if (e == NULL) { LOG(ERROR) << StringPrintf("%s: jni env is null", fn); return; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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(); LOG(ERROR) << StringPrintf("%s: fail notify", fn); } // let the tag-reading code handle NDEF data event android::nativeNfcTag_registerNdefTypeHandler(); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit", fn); } void PeerToPeer::llcpFirstPacketHandler(nfc_jni_native_data* nat) { static const char fn[] = "PeerToPeer::llcpFirstPacketHandler"; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", fn); JNIEnv* e = NULL; ScopedAttach attach(nat->vm, &e); if (e == NULL) { LOG(ERROR) << StringPrintf("%s: jni env is null", fn); return; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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(); LOG(ERROR) << StringPrintf("%s: fail notify", fn); } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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) { LOG(ERROR) << StringPrintf("%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"; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter; JNI handle: %u", fn, jniHandle); tNFA_STATUS nfaStat = NFA_STATUS_FAILED; sp<P2pServer> pSrv = NULL; bool isPollingTempStopped = false; mMutex.lock(); if ((pSrv = findServerLocked(jniHandle)) == NULL) { LOG(ERROR) << StringPrintf("%s: unknown service handle: %u", fn, jniHandle); mMutex.unlock(); return (false); } mMutex.unlock(); if (isDiscoveryStarted()) { isPollingTempStopped = true; startRfDiscovery(false); } { // 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) { LOG(ERROR) << StringPrintf("%s: deregister error=0x%X", fn, nfaStat); } removeServer(jniHandle); if (isPollingTempStopped) { startRfDiscovery(true); } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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_t miu, uint8_t rw) { static const char fn[] = "PeerToPeer::createClient"; int i = 0; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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) { LOG(ERROR) << StringPrintf("%s: fail", fn); return (false); } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: exit; new client jniHandle: %u NFA Handle: 0x%04x", fn, jniHandle, client->mClientConn->mNfaConnHandle); return (true); } else { LOG(ERROR) << StringPrintf( "%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 (int 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; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: deleted client handle: %u index: %u", fn, jniHandle, ii); return; } } // If the connection is for a server, just delete the connection for (int ii = 0; ii < sMax; ii++) { if (mServers[ii] != NULL) { if (mServers[ii]->removeServerConnection(jniHandle)) { return; } } } LOG(ERROR) << StringPrintf("%s: could not find handle: %u", fn, jniHandle); } /******************************************************************************* ** ** Function: connectConnOriented ** ** Description: Establish 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"; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: enter; h: %u service name=%s", fn, jniHandle, serviceName); bool stat = createDataLinkConn(jniHandle, serviceName, 0); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit; h: %u stat: %u", fn, jniHandle, stat); return stat; } /******************************************************************************* ** ** Function: connectConnOriented ** ** Description: Establish 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_t destinationSap) { static const char fn[] = "PeerToPeer::connectConnOriented"; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: enter; h: %u dest sap: 0x%X", fn, jniHandle, destinationSap); bool stat = createDataLinkConn(jniHandle, NULL, destinationSap); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit; h: %u stat: %u", fn, jniHandle, stat); return stat; } /******************************************************************************* ** ** Function: createDataLinkConn ** ** Description: Establish 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_t destinationSap) { static const char fn[] = "PeerToPeer::createDataLinkConn"; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter", fn); tNFA_STATUS nfaStat = NFA_STATUS_FAILED; sp<P2pClient> pClient = NULL; if ((pClient = findClient(jniHandle)) == NULL) { LOG(ERROR) << StringPrintf("%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) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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); LOG(ERROR) << StringPrintf("%s: fail; error=0x%X", fn, nfaStat); } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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 (int 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 (int 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 (int 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 (int 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_t* buffer, uint16_t bufferLen) { static const char fn[] = "PeerToPeer::send"; tNFA_STATUS nfaStat = NFA_STATUS_FAILED; sp<NfaConn> pConn = NULL; if ((pConn = findConnection(jniHandle)) == NULL) { LOG(ERROR) << StringPrintf("%s: can't find connection handle: %u", fn, jniHandle); return (false); } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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 { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: peer disconnected", fn); return (false); } } if (nfaStat == NFA_STATUS_OK) DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: exit OK; JNI handle: %u NFA Handle: 0x%04x", fn, jniHandle, pConn->mNfaConnHandle); else LOG(ERROR) << StringPrintf( "%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_t* buffer, uint16_t bufferLen, uint16_t& actualLen) { static const char fn[] = "PeerToPeer::receive"; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: enter; jniHandle: %u bufferLen: %u", fn, jniHandle, bufferLen); sp<NfaConn> pConn = NULL; tNFA_STATUS stat = NFA_STATUS_FAILED; uint32_t actualDataLen2 = 0; bool isMoreData = TRUE; bool retVal = false; if ((pConn = findConnection(jniHandle)) == NULL) { LOG(ERROR) << StringPrintf("%s: can't find connection handle: %u", fn, jniHandle); return (false); } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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_t)actualDataLen2; retVal = true; break; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: waiting for data...", fn); { SyncEventGuard guard(pConn->mReadEvent); pConn->mReadEvent.wait(); } } // while DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter; jni handle: %u", fn, jniHandle); if ((pConn = findConnection(jniHandle)) == NULL) { LOG(ERROR) << StringPrintf("%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) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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) LOG(ERROR) << StringPrintf("%s: fail p2p disconnect", fn); else pConn->mDisconnectingEvent.wait(); } mDisconnectMutex.lock(); removeConn(jniHandle); mDisconnectMutex.unlock(); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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_t PeerToPeer::getRemoteMaxInfoUnit(tJNI_HANDLE jniHandle) { static const char fn[] = "PeerToPeer::getRemoteMaxInfoUnit"; sp<NfaConn> pConn = NULL; if ((pConn = findConnection(jniHandle)) == NULL) { LOG(ERROR) << StringPrintf("%s: can't find client jniHandle: %u", fn, jniHandle); return 0; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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_t PeerToPeer::getRemoteRecvWindow(tJNI_HANDLE jniHandle) { static const char fn[] = "PeerToPeer::getRemoteRecvWindow"; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: client jni handle: %u", fn, jniHandle); sp<NfaConn> pConn = NULL; if ((pConn = findConnection(jniHandle)) == NULL) { LOG(ERROR) << StringPrintf("%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: getP2pListenMask ** ** Description: Get the set of technologies that P2P is listening. ** ** Returns: Set of technologies. ** *******************************************************************************/ tNFA_TECHNOLOGY_MASK PeerToPeer::getP2pListenMask() { return mP2pListenTechMask; } /******************************************************************************* ** ** Function: resetP2pListenMask ** ** Description: Reset the p2p listen technology mask to initial value. ** ** Returns: None. ** *******************************************************************************/ void PeerToPeer::resetP2pListenMask() { mP2pListenTechMask = NFA_TECHNOLOGY_MASK_A | NFA_TECHNOLOGY_MASK_F | NFA_TECHNOLOGY_MASK_A_ACTIVE | NFA_TECHNOLOGY_MASK_F_ACTIVE; if (NfcConfig::hasKey("P2P_LISTEN_TECH_MASK")) mP2pListenTechMask = NfcConfig::getUnsigned("P2P_LISTEN_TECH_MASK"); } /******************************************************************************* ** ** 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; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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 LOG(ERROR) << StringPrintf("%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 LOG(ERROR) << StringPrintf("%s: fail disable listen; error=0x%X", fn, nfaStat); } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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"; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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 (int 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 (int ii = 0; ii < sMax; ii++) { if (mServers[ii] != NULL) { mServers[ii]->unblockAll(); } } // loop } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter; event=0x%X", fn, p2pEvent); switch (p2pEvent) { case NFA_P2P_REG_SERVER_EVT: // NFA_P2pRegisterServer() has started to // listen DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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) { LOG(ERROR) << StringPrintf( "%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 DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_P2P_ACTIVATED_EVT; handle: 0x%04x", fn, eventData->activated.handle); break; case NFA_P2P_DEACTIVATED_EVT: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_P2P_DEACTIVATED_EVT; handle: 0x%04x", fn, eventData->activated.handle); break; case NFA_P2P_CONN_REQ_EVT: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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) { LOG(ERROR) << StringPrintf("%s: NFA_P2P_CONN_REQ_EVT; unknown server h", fn); return; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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) { LOG(ERROR) << StringPrintf( "%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; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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) { LOG(ERROR) << StringPrintf( "%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; { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_P2P_DISC_EVT; try guard disconn event", fn); SyncEventGuard guard3(pConn->mDisconnectingEvent); pConn->mDisconnectingEvent.notifyOne(); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_P2P_DISC_EVT; notified disconn event", fn); } { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_P2P_DISC_EVT; try guard congest event", fn); SyncEventGuard guard1(pConn->mCongEvent); pConn->mCongEvent.notifyOne(); // unblock write (if congested) DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_P2P_DISC_EVT; notified congest event", fn); } { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_P2P_DISC_EVT; try guard read event", fn); SyncEventGuard guard2(pConn->mReadEvent); pConn->mReadEvent.notifyOne(); // unblock receive() DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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) { LOG(ERROR) << StringPrintf( "%s: NFA_P2P_DATA_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->data.handle); } else { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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) { LOG(ERROR) << StringPrintf( "%s: NFA_P2P_CONGEST_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->congest.handle); } else { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: unknown event 0x%X ????", fn, p2pEvent); break; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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) { LOG(ERROR) << StringPrintf( "%s: NFA_P2P_REG_CLIENT_EVT: can't find waiting client", fn); } else { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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) { LOG(ERROR) << StringPrintf( "%s: NFA_P2P_ACTIVATED_EVT: can't find client", fn); } else { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_P2P_ACTIVATED_EVT; Conn Handle: 0x%04x, pClient: 0x%p", fn, eventData->activated.handle, pClient.get()); } break; case NFA_P2P_DEACTIVATED_EVT: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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) { LOG(ERROR) << StringPrintf( "%s: NFA_P2P_CONNECTED_EVT: can't find client: 0x%04x", fn, eventData->connected.client_handle); } else { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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: DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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) { LOG(ERROR) << StringPrintf( "%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; { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_P2P_DISC_EVT; try guard disconn event", fn); SyncEventGuard guard3(pConn->mDisconnectingEvent); pConn->mDisconnectingEvent.notifyOne(); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_P2P_DISC_EVT; notified disconn event", fn); } { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_P2P_DISC_EVT; try guard congest event", fn); SyncEventGuard guard1(pConn->mCongEvent); pConn->mCongEvent.notifyOne(); // unblock write (if congested) DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: NFA_P2P_DISC_EVT; notified congest event", fn); } { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: NFA_P2P_DISC_EVT; try guard read event", fn); SyncEventGuard guard2(pConn->mReadEvent); pConn->mReadEvent.notifyOne(); // unblock receive() DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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) { LOG(ERROR) << StringPrintf( "%s: NFA_P2P_DATA_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->data.handle); } else { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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) { LOG(ERROR) << StringPrintf( "%s: NFA_P2P_CONGEST_EVT: can't find conn for NFA handle: 0x%04x", fn, eventData->congest.handle); } else { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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: LOG(ERROR) << StringPrintf("%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_t 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"; DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: enter; service name: %s JNI handle: %u", fn, mServiceName.c_str(), mJniHandle); tNFA_STATUS stat = NFA_STATUS_OK; uint8_t 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) LOG(ERROR) << StringPrintf("%s: fail set LLCP config; error=0x%X", fn, stat); if (sSnepServiceName.compare(mServiceName) == 0) serverSap = 4; // 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) { LOG(ERROR) << StringPrintf("%s: fail register p2p server; error=0x%X", fn, stat); return (false); } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%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) { LOG(ERROR) << StringPrintf("%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); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: serverJniHandle: %u; connJniHandle: %u; wait for " "incoming connection", fn, serverJniHandle, connJniHandle); mConnRequestEvent.wait(); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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); DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("%s: no handle assigned", fn); return (false); } if (maxInfoUnit > (int)LLCP_MIU) { DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%s: overriding the miu passed by the app(%d) with stack miu(%zu)", fn, maxInfoUnit, LLCP_MIU); maxInfoUnit = LLCP_MIU; } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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) { LOG(ERROR) << StringPrintf("%s: fail to accept remote; error=0x%X", fn, nfaStat); return (false); } DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf( "%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) {}