summaryrefslogtreecommitdiffstats
path: root/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp')
-rw-r--r--nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp227
1 files changed, 227 insertions, 0 deletions
diff --git a/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp
new file mode 100644
index 0000000..2fccfc9
--- /dev/null
+++ b/nxp/jni/com_android_nfc_NativeLlcpServiceSocket.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#include <semaphore.h>
+#include <errno.h>
+
+#include "com_android_nfc.h"
+
+namespace android {
+
+extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext,
+ uint8_t nErrCode);
+/*
+ * Callbacks
+ */
+static void nfc_jni_llcp_accept_socket_callback(void* pContext,
+ NFCSTATUS status)
+{
+ struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
+ LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status);
+
+ /* Report the callback status and wake up the caller */
+ pCallbackData->status = status;
+ sem_post(&pCallbackData->sem);
+}
+
+
+/*
+ * Utils
+ */
+
+static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor,
+ phLibNfc_Handle hServerSocket)
+{
+ nfc_jni_listen_data_t * pListenData;
+ phLibNfc_Handle pIncomingSocket = NULL;
+
+ /* Look for a pending incoming connection on the current server */
+ LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries)
+ {
+ if (pListenData->pServerSocket == hServerSocket)
+ {
+ pIncomingSocket = pListenData->pIncomingSocket;
+ LIST_REMOVE(pListenData, entries);
+ free(pListenData);
+ break;
+ }
+ }
+
+ return pIncomingSocket;
+}
+
+/*
+ * Methods
+ */
+static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength)
+{
+ NFCSTATUS ret = NFCSTATUS_SUCCESS;
+ struct timespec ts;
+ phLibNfc_Llcp_sSocketOptions_t sOptions;
+ phNfc_sData_t sWorkingBuffer;
+ jfieldID f;
+ jclass clsNativeLlcpSocket;
+ jobject clientSocket = NULL;
+ struct nfc_jni_callback_data cb_data;
+ phLibNfc_Handle hIncomingSocket, hServerSocket;
+ nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor();
+
+ /* Create the local semaphore */
+ if (!nfc_cb_data_init(&cb_data, NULL))
+ {
+ goto clean_and_return;
+ }
+
+ /* Get server socket */
+ hServerSocket = nfc_jni_get_nfc_socket_handle(e,o);
+
+ /* Set socket options with the socket options of the service */
+ sOptions.miu = miu;
+ sOptions.rw = rw;
+
+ /* Allocate Working buffer length */
+ sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength);
+ sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength;
+
+ while(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ /* Wait for tag Notification */
+ pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
+ while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) {
+ pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex);
+ }
+ pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);
+
+ /* Accept the incomming socket */
+ TRACE("phLibNfc_Llcp_Accept()");
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Accept( hIncomingSocket,
+ &sOptions,
+ &sWorkingBuffer,
+ nfc_jni_llcp_transport_socket_err_callback,
+ nfc_jni_llcp_accept_socket_callback,
+ (void*)&cb_data);
+ REENTRANCE_UNLOCK();
+ if(ret != NFCSTATUS_PENDING)
+ {
+ // NOTE: This may happen if link went down since incoming socket detected, then
+ // just drop it and start a new accept loop.
+ ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+ continue;
+ }
+ TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
+
+ /* Wait for callback response */
+ if(sem_wait(&cb_data.sem))
+ {
+ ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
+ goto clean_and_return;
+ }
+
+ if(cb_data.status != NFCSTATUS_SUCCESS)
+ {
+ /* NOTE: Do not generate an error if the accept failed to avoid error in server application */
+ ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status));
+ }
+ }
+
+ /* Create new LlcpSocket object */
+ if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeLlcpSocket",&(clientSocket)) == -1)
+ {
+ ALOGD("LLCP Socket creation error");
+ goto clean_and_return;
+ }
+
+ /* Get NativeConnectionOriented class object */
+ clsNativeLlcpSocket = e->GetObjectClass(clientSocket);
+ if(e->ExceptionCheck())
+ {
+ ALOGD("LLCP Socket get class object error");
+ goto clean_and_return;
+ }
+
+ /* Set socket handle */
+ f = e->GetFieldID(clsNativeLlcpSocket, "mHandle", "I");
+ e->SetIntField(clientSocket, f,(jint)hIncomingSocket);
+
+ /* Set socket MIU */
+ f = e->GetFieldID(clsNativeLlcpSocket, "mLocalMiu", "I");
+ e->SetIntField(clientSocket, f,(jint)miu);
+
+ /* Set socket RW */
+ f = e->GetFieldID(clsNativeLlcpSocket, "mLocalRw", "I");
+ e->SetIntField(clientSocket, f,(jint)rw);
+
+ TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw);
+
+clean_and_return:
+ nfc_cb_data_deinit(&cb_data);
+ return clientSocket;
+}
+
+static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o)
+{
+ NFCSTATUS ret;
+ phLibNfc_Handle hLlcpSocket;
+ nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor();
+
+ TRACE("Close Service socket");
+
+ /* Retrieve socket handle */
+ hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
+
+ pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
+ /* TODO: implement accept abort */
+ pthread_cond_broadcast(&pMonitor->incoming_socket_cond);
+ pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);
+
+ REENTRANCE_LOCK();
+ ret = phLibNfc_Llcp_Close(hLlcpSocket);
+ REENTRANCE_UNLOCK();
+ if(ret == NFCSTATUS_SUCCESS)
+ {
+ TRACE("Close Service socket OK");
+ return TRUE;
+ }
+ else
+ {
+ ALOGD("Close Service socket KO");
+ return FALSE;
+ }
+}
+
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gMethods[] =
+{
+ {"doAccept", "(III)Lcom/android/nfc/dhimpl/NativeLlcpSocket;",
+ (void *)com_NativeLlcpServiceSocket_doAccept},
+
+ {"doClose", "()Z",
+ (void *)com_NativeLlcpServiceSocket_doClose},
+};
+
+
+int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e)
+{
+ return jniRegisterNativeMethods(e,
+ "com/android/nfc/dhimpl/NativeLlcpServiceSocket",
+ gMethods, NELEM(gMethods));
+}
+
+} // namespace android