Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <semaphore.h>
     18 #include <errno.h>
     19 #include <ScopedLocalRef.h>
     20 
     21 #include "com_android_nfc.h"
     22 
     23 namespace android {
     24 
     25 extern void nfc_jni_llcp_transport_socket_err_callback(void*      pContext,
     26                                                        uint8_t    nErrCode);
     27 /*
     28  * Callbacks
     29  */
     30 static void nfc_jni_llcp_accept_socket_callback(void*        pContext,
     31                                                 NFCSTATUS    status)
     32 {
     33    struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
     34    LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status);
     35 
     36    /* Report the callback status and wake up the caller */
     37    pCallbackData->status = status;
     38    sem_post(&pCallbackData->sem);
     39 }
     40 
     41 
     42 /*
     43  * Utils
     44  */
     45 
     46 static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor,
     47                                                  phLibNfc_Handle hServerSocket)
     48 {
     49    nfc_jni_listen_data_t * pListenData;
     50    phLibNfc_Handle pIncomingSocket = (phLibNfc_Handle)NULL;
     51 
     52    /* Look for a pending incoming connection on the current server */
     53    LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries)
     54    {
     55       if (pListenData->pServerSocket == hServerSocket)
     56       {
     57          pIncomingSocket = pListenData->pIncomingSocket;
     58          LIST_REMOVE(pListenData, entries);
     59          free(pListenData);
     60          break;
     61       }
     62    }
     63 
     64    return pIncomingSocket;
     65 }
     66 
     67 /*
     68  * Methods
     69  */
     70 static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength)
     71 {
     72    NFCSTATUS ret = NFCSTATUS_SUCCESS;
     73    struct timespec ts;
     74    phLibNfc_Llcp_sSocketOptions_t sOptions;
     75    phNfc_sData_t sWorkingBuffer;
     76    jfieldID f;
     77    ScopedLocalRef<jclass> clsNativeLlcpSocket(e, NULL);
     78    jobject clientSocket = NULL;
     79    struct nfc_jni_callback_data cb_data;
     80    phLibNfc_Handle hIncomingSocket, hServerSocket;
     81    nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor();
     82 
     83    hIncomingSocket = (phLibNfc_Handle)NULL;
     84 
     85    /* Create the local semaphore */
     86    if (!nfc_cb_data_init(&cb_data, NULL))
     87    {
     88       goto clean_and_return;
     89    }
     90 
     91    /* Get server socket */
     92    hServerSocket = nfc_jni_get_nfc_socket_handle(e,o);
     93 
     94    /* Set socket options with the socket options of the service */
     95    sOptions.miu = miu;
     96    sOptions.rw = rw;
     97 
     98    /* Allocate Working buffer length */
     99    sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength);
    100    sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength;
    101 
    102    while(cb_data.status != NFCSTATUS_SUCCESS)
    103    {
    104       /* Wait for tag Notification */
    105       pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
    106       while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == (phLibNfc_Handle)NULL) {
    107          pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex);
    108       }
    109       pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);
    110 
    111       /* Accept the incomming socket */
    112       TRACE("phLibNfc_Llcp_Accept()");
    113       REENTRANCE_LOCK();
    114       ret = phLibNfc_Llcp_Accept( hIncomingSocket,
    115                                   &sOptions,
    116                                   &sWorkingBuffer,
    117                                   nfc_jni_llcp_transport_socket_err_callback,
    118                                   nfc_jni_llcp_accept_socket_callback,
    119                                   (void*)&cb_data);
    120       REENTRANCE_UNLOCK();
    121       if(ret != NFCSTATUS_PENDING)
    122       {
    123          // NOTE: This may happen if link went down since incoming socket detected, then
    124          //       just drop it and start a new accept loop.
    125          ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    126          continue;
    127       }
    128       TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    129 
    130       /* Wait for callback response */
    131       if(sem_wait(&cb_data.sem))
    132       {
    133          ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
    134          goto clean_and_return;
    135       }
    136 
    137       if(cb_data.status != NFCSTATUS_SUCCESS)
    138       {
    139          /* NOTE: Do not generate an error if the accept failed to avoid error in server application */
    140          ALOGD("Failed to accept incoming socket  0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status));
    141       }
    142    }
    143 
    144    /* Create new LlcpSocket object */
    145    if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeLlcpSocket",&(clientSocket)) == -1)
    146    {
    147       ALOGD("LLCP Socket creation error");
    148       goto clean_and_return;
    149    }
    150 
    151    /* Get NativeConnectionOriented class object */
    152    clsNativeLlcpSocket.reset(e->GetObjectClass(clientSocket));
    153    if(e->ExceptionCheck())
    154    {
    155       ALOGD("LLCP Socket get class object error");
    156       goto clean_and_return;
    157    }
    158 
    159    /* Set socket handle */
    160    f = e->GetFieldID(clsNativeLlcpSocket.get(), "mHandle", "I");
    161    e->SetIntField(clientSocket, f,(jint)hIncomingSocket);
    162 
    163    /* Set socket MIU */
    164    f = e->GetFieldID(clsNativeLlcpSocket.get(), "mLocalMiu", "I");
    165    e->SetIntField(clientSocket, f,(jint)miu);
    166 
    167    /* Set socket RW */
    168    f = e->GetFieldID(clsNativeLlcpSocket.get(), "mLocalRw", "I");
    169    e->SetIntField(clientSocket, f,(jint)rw);
    170 
    171    TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw);
    172 
    173 clean_and_return:
    174    nfc_cb_data_deinit(&cb_data);
    175    return clientSocket;
    176 }
    177 
    178 static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o)
    179 {
    180    NFCSTATUS ret;
    181    phLibNfc_Handle hLlcpSocket;
    182    nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor();
    183 
    184    TRACE("Close Service socket");
    185 
    186    /* Retrieve socket handle */
    187    hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
    188 
    189    pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
    190    /* TODO: implement accept abort */
    191    pthread_cond_broadcast(&pMonitor->incoming_socket_cond);
    192    pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);
    193 
    194    REENTRANCE_LOCK();
    195    ret = phLibNfc_Llcp_Close(hLlcpSocket);
    196    REENTRANCE_UNLOCK();
    197    if(ret == NFCSTATUS_SUCCESS)
    198    {
    199       TRACE("Close Service socket OK");
    200       return TRUE;
    201    }
    202    else
    203    {
    204       ALOGD("Close Service socket KO");
    205       return FALSE;
    206    }
    207 }
    208 
    209 
    210 /*
    211  * JNI registration.
    212  */
    213 static JNINativeMethod gMethods[] =
    214 {
    215    {"doAccept", "(III)Lcom/android/nfc/dhimpl/NativeLlcpSocket;",
    216       (void *)com_NativeLlcpServiceSocket_doAccept},
    217 
    218    {"doClose", "()Z",
    219       (void *)com_NativeLlcpServiceSocket_doClose},
    220 };
    221 
    222 
    223 int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e)
    224 {
    225    return jniRegisterNativeMethods(e,
    226       "com/android/nfc/dhimpl/NativeLlcpServiceSocket",
    227       gMethods, NELEM(gMethods));
    228 }
    229 
    230 } // namespace android
    231