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 extern "C" 23 { 24 #include "nfa_api.h" 25 #include "nfa_p2p_api.h" 26 } 27 28 29 namespace android 30 { 31 32 33 /***************************************************************************** 34 ** 35 ** private variables and functions 36 ** 37 *****************************************************************************/ 38 static sem_t sConnlessRecvSem; 39 static jboolean sConnlessRecvWaitingForData = JNI_FALSE; 40 static uint8_t* sConnlessRecvBuf = NULL; 41 static uint32_t sConnlessRecvLen = 0; 42 static uint32_t sConnlessRecvRemoteSap = 0; 43 44 45 /******************************************************************************* 46 ** 47 ** Function: nativeLlcpConnectionlessSocket_doSendTo 48 ** 49 ** Description: Send data to peer. 50 ** e: JVM environment. 51 ** o: Java object. 52 ** nsap: service access point. 53 ** data: buffer for data. 54 ** 55 ** Returns: True if ok. 56 ** 57 *******************************************************************************/ 58 static jboolean nativeLlcpConnectionlessSocket_doSendTo (JNIEnv *e, jobject o, jint nsap, jbyteArray data) 59 { 60 tNFA_STATUS status = NFA_STATUS_FAILED; 61 jint handle = 0; 62 uint8_t* buf = NULL; 63 uint32_t len = 0; 64 jclass c = NULL; 65 jfieldID f = NULL; 66 67 ALOGD ("%s: nsap = %d", __FUNCTION__, nsap); 68 69 c = e->GetObjectClass (o); 70 f = e->GetFieldID (c, "mHandle", "I"); 71 handle = e->GetIntField (o, f); 72 73 buf = (uint8_t*) e->GetByteArrayElements (data, NULL); 74 len = (uint32_t) e->GetArrayLength (data); 75 76 ALOGD ("NFA_P2pSendUI: len = %d", len); 77 status = NFA_P2pSendUI ((tNFA_HANDLE) handle, nsap, len, buf); 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 o, jint linkMiu) 173 { 174 jbyteArray receivedData = NULL; 175 jobject llcpPacket = NULL; 176 jclass clsLlcpPacket = NULL; 177 jfieldID f = NULL; 178 179 ALOGD ("%s: linkMiu = %d", __FUNCTION__, linkMiu); 180 181 if (sConnlessRecvWaitingForData != JNI_FALSE) 182 { 183 ALOGD ("%s: Already waiting for incoming data", __FUNCTION__); 184 return NULL; 185 } 186 187 sConnlessRecvBuf = (uint8_t*) malloc (linkMiu); 188 if (sConnlessRecvBuf == NULL) 189 { 190 ALOGD ("%s: Failed to allocate %d bytes memory buffer", __FUNCTION__, linkMiu); 191 return NULL; 192 } 193 sConnlessRecvLen = linkMiu; 194 195 // Create the write semaphore 196 if (sem_init (&sConnlessRecvSem, 0, 0) == -1) 197 { 198 ALOGE ("%s: semaphore creation failed (errno=0x%08x)", __FUNCTION__, errno); 199 return connectionlessCleanup (); 200 } 201 202 sConnlessRecvWaitingForData = JNI_TRUE; 203 204 // Wait for sConnlessRecvSem completion status 205 if (sem_wait (&sConnlessRecvSem)) 206 { 207 ALOGE ("%s: Failed to wait for write semaphore (errno=0x%08x)", __FUNCTION__, errno); 208 goto TheEnd; 209 } 210 211 // Create new LlcpPacket object 212 if (nfc_jni_cache_object (e, "com/android/nfc/LlcpPacket", &(llcpPacket)) == -1) 213 { 214 ALOGE ("%s: Find LlcpPacket class error", __FUNCTION__); 215 return connectionlessCleanup (); 216 } 217 218 // Get NativeConnectionless class object 219 clsLlcpPacket = e->GetObjectClass (llcpPacket); 220 if (e->ExceptionCheck ()) 221 { 222 e->ExceptionClear(); 223 ALOGE ("%s: Get Object class error", __FUNCTION__); 224 return connectionlessCleanup (); 225 } 226 227 // Set Llcp Packet remote SAP 228 f = e->GetFieldID (clsLlcpPacket, "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, "mDataBuffer", "[B"); 234 receivedData = e->NewByteArray (sConnlessRecvLen); 235 e->SetByteArrayRegion (receivedData, 0, sConnlessRecvLen, (jbyte*) sConnlessRecvBuf); 236 e->SetObjectField (llcpPacket, f, receivedData); 237 238 TheEnd: 239 connectionlessCleanup (); 240 if (sem_destroy (&sConnlessRecvSem)) 241 { 242 ALOGE ("%s: Failed to destroy sConnlessRecvSem semaphore (errno=0x%08x)", __FUNCTION__, errno); 243 } 244 return llcpPacket; 245 } 246 247 248 /******************************************************************************* 249 ** 250 ** Function: nativeLlcpConnectionlessSocket_doClose 251 ** 252 ** Description: Close socket. 253 ** e: JVM environment. 254 ** o: Java object. 255 ** 256 ** Returns: True if ok. 257 ** 258 *******************************************************************************/ 259 static jboolean nativeLlcpConnectionlessSocket_doClose (JNIEnv *e, jobject o) 260 { 261 tNFA_STATUS status = NFA_STATUS_FAILED; 262 jint handle = 0; 263 jclass c = NULL; 264 jfieldID f = NULL; 265 266 ALOGD ("%s", __FUNCTION__); 267 268 c = e->GetObjectClass (o); 269 f = e->GetFieldID (c, "mHandle", "I"); 270 handle = e->GetIntField (o, f); 271 272 status = NFA_P2pDisconnect ((tNFA_HANDLE) handle, FALSE); 273 if (status != NFA_STATUS_OK) 274 { 275 ALOGE ("%s: disconnect failed, status = %d", __FUNCTION__, status); 276 return JNI_FALSE; 277 } 278 return JNI_TRUE; 279 } 280 281 282 /***************************************************************************** 283 ** 284 ** Description: JNI functions 285 ** 286 *****************************************************************************/ 287 static JNINativeMethod gMethods[] = 288 { 289 {"doSendTo", "(I[B)Z", (void*) nativeLlcpConnectionlessSocket_doSendTo}, 290 {"doReceiveFrom", "(I)Lcom/android/nfc/LlcpPacket;", (void*) nativeLlcpConnectionlessSocket_doReceiveFrom}, 291 {"doClose", "()Z", (void*) nativeLlcpConnectionlessSocket_doClose}, 292 }; 293 294 295 /******************************************************************************* 296 ** 297 ** Function: register_com_android_nfc_NativeLlcpConnectionlessSocket 298 ** 299 ** Description: Regisgter JNI functions with Java Virtual Machine. 300 ** e: Environment of JVM. 301 ** 302 ** Returns: Status of registration. 303 ** 304 *******************************************************************************/ 305 int register_com_android_nfc_NativeLlcpConnectionlessSocket (JNIEnv *e) 306 { 307 return jniRegisterNativeMethods (e, gNativeLlcpConnectionlessSocketClassName, gMethods, NELEM(gMethods)); 308 } 309 310 311 } // android namespace 312