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/nxp/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/nxp/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/nxp/NativeLlcpServiceSocket", 224 gMethods, NELEM(gMethods)); 225 } 226 227 } // namespace android 228