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