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