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