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