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 = 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    /* Create the local semaphore */
     84    if (!nfc_cb_data_init(&cb_data, NULL))
     85    {
     86       goto clean_and_return;
     87    }
     88 
     89    /* Get server socket */
     90    hServerSocket = nfc_jni_get_nfc_socket_handle(e,o);
     91 
     92    /* Set socket options with the socket options of the service */
     93    sOptions.miu = miu;
     94    sOptions.rw = rw;
     95 
     96    /* Allocate Working buffer length */
     97    sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength);
     98    sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength;
     99 
    100    while(cb_data.status != NFCSTATUS_SUCCESS)
    101    {
    102       /* Wait for tag Notification */
    103       pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
    104       while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == NULL) {
    105          pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex);
    106       }
    107       pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);
    108 
    109       /* Accept the incomming socket */
    110       TRACE("phLibNfc_Llcp_Accept()");
    111       REENTRANCE_LOCK();
    112       ret = phLibNfc_Llcp_Accept( hIncomingSocket,
    113                                   &sOptions,
    114                                   &sWorkingBuffer,
    115                                   nfc_jni_llcp_transport_socket_err_callback,
    116                                   nfc_jni_llcp_accept_socket_callback,
    117                                   (void*)&cb_data);
    118       REENTRANCE_UNLOCK();
    119       if(ret != NFCSTATUS_PENDING)
    120       {
    121          // NOTE: This may happen if link went down since incoming socket detected, then
    122          //       just drop it and start a new accept loop.
    123          ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    124          continue;
    125       }
    126       TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
    127 
    128       /* Wait for callback response */
    129       if(sem_wait(&cb_data.sem))
    130       {
    131          ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
    132          goto clean_and_return;
    133       }
    134 
    135       if(cb_data.status != NFCSTATUS_SUCCESS)
    136       {
    137          /* NOTE: Do not generate an error if the accept failed to avoid error in server application */
    138          ALOGD("Failed to accept incoming socket  0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status));
    139       }
    140    }
    141 
    142    /* Create new LlcpSocket object */
    143    if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeLlcpSocket",&(clientSocket)) == -1)
    144    {
    145       ALOGD("LLCP Socket creation error");
    146       goto clean_and_return;
    147    }
    148 
    149    /* Get NativeConnectionOriented class object */
    150    clsNativeLlcpSocket.reset(e->GetObjectClass(clientSocket));
    151    if(e->ExceptionCheck())
    152    {
    153       ALOGD("LLCP Socket get class object error");
    154       goto clean_and_return;
    155    }
    156 
    157    /* Set socket handle */
    158    f = e->GetFieldID(clsNativeLlcpSocket.get(), "mHandle", "I");
    159    e->SetIntField(clientSocket, f,(jint)hIncomingSocket);
    160 
    161    /* Set socket MIU */
    162    f = e->GetFieldID(clsNativeLlcpSocket.get(), "mLocalMiu", "I");
    163    e->SetIntField(clientSocket, f,(jint)miu);
    164 
    165    /* Set socket RW */
    166    f = e->GetFieldID(clsNativeLlcpSocket.get(), "mLocalRw", "I");
    167    e->SetIntField(clientSocket, f,(jint)rw);
    168 
    169    TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw);
    170 
    171 clean_and_return:
    172    nfc_cb_data_deinit(&cb_data);
    173    return clientSocket;
    174 }
    175 
    176 static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o)
    177 {
    178    NFCSTATUS ret;
    179    phLibNfc_Handle hLlcpSocket;
    180    nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor();
    181 
    182    TRACE("Close Service socket");
    183 
    184    /* Retrieve socket handle */
    185    hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
    186 
    187    pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
    188    /* TODO: implement accept abort */
    189    pthread_cond_broadcast(&pMonitor->incoming_socket_cond);
    190    pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);
    191 
    192    REENTRANCE_LOCK();
    193    ret = phLibNfc_Llcp_Close(hLlcpSocket);
    194    REENTRANCE_UNLOCK();
    195    if(ret == NFCSTATUS_SUCCESS)
    196    {
    197       TRACE("Close Service socket OK");
    198       return TRUE;
    199    }
    200    else
    201    {
    202       ALOGD("Close Service socket KO");
    203       return FALSE;
    204    }
    205 }
    206 
    207 
    208 /*
    209  * JNI registration.
    210  */
    211 static JNINativeMethod gMethods[] =
    212 {
    213    {"doAccept", "(III)Lcom/android/nfc/dhimpl/NativeLlcpSocket;",
    214       (void *)com_NativeLlcpServiceSocket_doAccept},
    215 
    216    {"doClose", "()Z",
    217       (void *)com_NativeLlcpServiceSocket_doClose},
    218 };
    219 
    220 
    221 int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e)
    222 {
    223    return jniRegisterNativeMethods(e,
    224       "com/android/nfc/dhimpl/NativeLlcpServiceSocket",
    225       gMethods, NELEM(gMethods));
    226 }
    227 
    228 } // namespace android
    229