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