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 24namespace android { 25 26extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext, 27 uint8_t nErrCode); 28/* 29 * Callbacks 30 */ 31static 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 47static 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 */ 71static 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 174clean_and_return: 175 nfc_cb_data_deinit(&cb_data); 176 return clientSocket; 177} 178 179static 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 */ 214static 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 224int 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