1 /* 2 * Copyright (C) 2012 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 "OverrideLog.h" 20 #include "NfcJniUtil.h" 21 #include "JavaClassConstants.h" 22 #include <ScopedLocalRef.h> 23 #include <ScopedPrimitiveArray.h> 24 extern "C" 25 { 26 #include "nfa_api.h" 27 #include "nfa_p2p_api.h" 28 } 29 30 31 namespace android 32 { 33 34 35 /***************************************************************************** 36 ** 37 ** private variables and functions 38 ** 39 *****************************************************************************/ 40 static sem_t sConnlessRecvSem; 41 static jboolean sConnlessRecvWaitingForData = JNI_FALSE; 42 static uint8_t* sConnlessRecvBuf = NULL; 43 static uint32_t sConnlessRecvLen = 0; 44 static uint32_t sConnlessRecvRemoteSap = 0; 45 46 47 /******************************************************************************* 48 ** 49 ** Function: nativeLlcpConnectionlessSocket_doSendTo 50 ** 51 ** Description: Send data to peer. 52 ** e: JVM environment. 53 ** o: Java object. 54 ** nsap: service access point. 55 ** data: buffer for data. 56 ** 57 ** Returns: True if ok. 58 ** 59 *******************************************************************************/ 60 static jboolean nativeLlcpConnectionlessSocket_doSendTo (JNIEnv *e, jobject o, jint nsap, jbyteArray data) 61 { 62 ALOGD ("%s: nsap = %d", __FUNCTION__, nsap); 63 64 ScopedLocalRef<jclass> c(e, e->GetObjectClass(o)); 65 jfieldID f = e->GetFieldID(c.get(), "mHandle", "I"); 66 jint handle = e->GetIntField(o, f); 67 68 ScopedByteArrayRO bytes(e, data); 69 if (bytes.get() == NULL) { 70 return JNI_FALSE; 71 } 72 size_t byte_count = bytes.size(); 73 74 ALOGD("NFA_P2pSendUI: len = %d", byte_count); 75 UINT8* raw_ptr = const_cast<UINT8*>(reinterpret_cast<const UINT8*>(&bytes[0])); // TODO: API bug; NFA_P2pSendUI should take const*! 76 tNFA_STATUS status = NFA_P2pSendUI((tNFA_HANDLE) handle, nsap, byte_count, raw_ptr); 77 78 ALOGD("%s: NFA_P2pSendUI done, status = %d", __FUNCTION__, status); 79 if (status != NFA_STATUS_OK) { 80 ALOGE("%s: NFA_P2pSendUI failed, status = %d", __FUNCTION__, status); 81 return JNI_FALSE; 82 } 83 return JNI_TRUE; 84 } 85 86 87 /******************************************************************************* 88 ** 89 ** Function: nativeLlcpConnectionlessSocket_receiveData 90 ** 91 ** Description: Receive data from the stack. 92 ** data: buffer contains data. 93 ** len: length of data. 94 ** remoteSap: remote service access point. 95 ** 96 ** Returns: None 97 ** 98 *******************************************************************************/ 99 void nativeLlcpConnectionlessSocket_receiveData (uint8_t* data, uint32_t len, uint32_t remoteSap) 100 { 101 ALOGD ("%s: waiting for data = %d, len = %d", __FUNCTION__, sConnlessRecvWaitingForData, len); 102 103 // Sanity... 104 if (sConnlessRecvLen < len) 105 { 106 len = sConnlessRecvLen; 107 } 108 109 if (sConnlessRecvWaitingForData) 110 { 111 sConnlessRecvWaitingForData = JNI_FALSE; 112 sConnlessRecvLen = len; 113 memcpy (sConnlessRecvBuf, data, len); 114 sConnlessRecvRemoteSap = remoteSap; 115 116 sem_post (&sConnlessRecvSem); 117 } 118 } 119 120 121 /******************************************************************************* 122 ** 123 ** Function: connectionlessCleanup 124 ** 125 ** Description: Free resources. 126 ** 127 ** Returns: None 128 ** 129 *******************************************************************************/ 130 static jobject connectionlessCleanup () 131 { 132 sConnlessRecvWaitingForData = JNI_FALSE; 133 sConnlessRecvLen = 0; 134 if (sConnlessRecvBuf != NULL) 135 { 136 free (sConnlessRecvBuf); 137 sConnlessRecvBuf = NULL; 138 } 139 return NULL; 140 } 141 142 143 /******************************************************************************* 144 ** 145 ** Function: nativeLlcpConnectionlessSocket_abortWait 146 ** 147 ** Description: Abort current operation and unblock threads. 148 ** 149 ** Returns: None 150 ** 151 *******************************************************************************/ 152 void nativeLlcpConnectionlessSocket_abortWait () 153 { 154 sem_post (&sConnlessRecvSem); 155 } 156 157 158 /******************************************************************************* 159 ** 160 ** Function: nativeLlcpConnectionlessSocket_doReceiveFrom 161 ** 162 ** Description: Receive data from a peer. 163 ** e: JVM environment. 164 ** o: Java object. 165 ** linkMiu: max info unit 166 ** 167 ** Returns: LlcpPacket Java object. 168 ** 169 *******************************************************************************/ 170 static jobject nativeLlcpConnectionlessSocket_doReceiveFrom (JNIEnv* e, jobject, jint linkMiu) 171 { 172 ALOGD ("%s: linkMiu = %d", __FUNCTION__, linkMiu); 173 jobject llcpPacket = NULL; 174 ScopedLocalRef<jclass> clsLlcpPacket(e, NULL); 175 176 if (sConnlessRecvWaitingForData != JNI_FALSE) 177 { 178 ALOGD ("%s: Already waiting for incoming data", __FUNCTION__); 179 return NULL; 180 } 181 182 sConnlessRecvBuf = (uint8_t*) malloc (linkMiu); 183 if (sConnlessRecvBuf == NULL) 184 { 185 ALOGD ("%s: Failed to allocate %d bytes memory buffer", __FUNCTION__, linkMiu); 186 return NULL; 187 } 188 sConnlessRecvLen = linkMiu; 189 190 // Create the write semaphore 191 if (sem_init (&sConnlessRecvSem, 0, 0) == -1) 192 { 193 ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno); 194 return connectionlessCleanup (); 195 } 196 197 sConnlessRecvWaitingForData = JNI_TRUE; 198 199 // Wait for sConnlessRecvSem completion status 200 if (sem_wait (&sConnlessRecvSem)) 201 { 202 ALOGE ("%s: Failed to wait for write semaphore (errno=0x%08x)", __FUNCTION__, errno); 203 goto TheEnd; 204 } 205 206 // Create new LlcpPacket object 207 if (nfc_jni_cache_object (e, "com/android/nfc/LlcpPacket", &(llcpPacket)) == -1) 208 { 209 ALOGE ("%s: Find LlcpPacket class error", __FUNCTION__); 210 return connectionlessCleanup (); 211 } 212 213 // Get NativeConnectionless class object 214 clsLlcpPacket.reset(e->GetObjectClass(llcpPacket)); 215 if (e->ExceptionCheck()) 216 { 217 e->ExceptionClear(); 218 ALOGE ("%s: Get Object class error", __FUNCTION__); 219 return connectionlessCleanup (); 220 } 221 222 // Set Llcp Packet remote SAP 223 jfieldID f; 224 f = e->GetFieldID(clsLlcpPacket.get(), "mRemoteSap", "I"); 225 e->SetIntField(llcpPacket, f, (jbyte) sConnlessRecvRemoteSap); 226 227 // Set Llcp Packet Buffer 228 ALOGD ("%s: Received Llcp packet buffer size = %d\n", __FUNCTION__, sConnlessRecvLen); 229 f = e->GetFieldID(clsLlcpPacket.get(), "mDataBuffer", "[B"); 230 231 { 232 ScopedLocalRef<jbyteArray> receivedData(e, e->NewByteArray(sConnlessRecvLen)); 233 e->SetByteArrayRegion(receivedData.get(), 0, sConnlessRecvLen, (jbyte*) sConnlessRecvBuf); 234 e->SetObjectField(llcpPacket, f, receivedData.get()); 235 } 236 237 TheEnd: // TODO: should all the "return connectionlessCleanup()"s in this function jump here instead? 238 connectionlessCleanup (); 239 if (sem_destroy (&sConnlessRecvSem)) 240 { 241 ALOGE ("%s: Failed to destroy sConnlessRecvSem semaphore (errno=0x%08x)", __FUNCTION__, errno); 242 } 243 return llcpPacket; 244 } 245 246 247 /******************************************************************************* 248 ** 249 ** Function: nativeLlcpConnectionlessSocket_doClose 250 ** 251 ** Description: Close socket. 252 ** e: JVM environment. 253 ** o: Java object. 254 ** 255 ** Returns: True if ok. 256 ** 257 *******************************************************************************/ 258 static jboolean nativeLlcpConnectionlessSocket_doClose (JNIEnv *e, jobject o) 259 { 260 ALOGD ("%s", __FUNCTION__); 261 262 ScopedLocalRef<jclass> c(e, e->GetObjectClass(o)); 263 jfieldID f = e->GetFieldID(c.get(), "mHandle", "I"); 264 jint handle = e->GetIntField(o, f); 265 266 tNFA_STATUS status = NFA_P2pDisconnect((tNFA_HANDLE) handle, FALSE); 267 if (status != NFA_STATUS_OK) { 268 ALOGE ("%s: disconnect failed, status = %d", __FUNCTION__, status); 269 return JNI_FALSE; 270 } 271 return JNI_TRUE; 272 } 273 274 275 /***************************************************************************** 276 ** 277 ** Description: JNI functions 278 ** 279 *****************************************************************************/ 280 static JNINativeMethod gMethods[] = 281 { 282 {"doSendTo", "(I[B)Z", (void*) nativeLlcpConnectionlessSocket_doSendTo}, 283 {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void*) nativeLlcpConnectionlessSocket_doReceiveFrom}, 284 {"doClose", "()Z", (void*) nativeLlcpConnectionlessSocket_doClose}, 285 }; 286 287 288 /******************************************************************************* 289 ** 290 ** Function: register_com_android_nfc_NativeLlcpConnectionlessSocket 291 ** 292 ** Description: Regisgter JNI functions with Java Virtual Machine. 293 ** e: Environment of JVM. 294 ** 295 ** Returns: Status of registration. 296 ** 297 *******************************************************************************/ 298 int register_com_android_nfc_NativeLlcpConnectionlessSocket (JNIEnv *e) 299 { 300 return jniRegisterNativeMethods (e, gNativeLlcpConnectionlessSocketClassName, gMethods, NELEM(gMethods)); 301 } 302 303 304 } // android namespace 305