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