You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1871 lines
65 KiB
1871 lines
65 KiB
/*
|
|
* 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, it may not be connected yet, so unblock it 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) {}
|