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