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 *******************************************************************************/
nativeLlcpConnectionlessSocket_doSendTo(JNIEnv * e,jobject o,jint nsap,jbyteArray data)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 *******************************************************************************/
nativeLlcpConnectionlessSocket_receiveData(uint8_t * data,uint32_t len,uint32_t remoteSap)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 *******************************************************************************/
connectionlessCleanup()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 *******************************************************************************/
nativeLlcpConnectionlessSocket_abortWait()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 *******************************************************************************/
nativeLlcpConnectionlessSocket_doReceiveFrom(JNIEnv * e,jobject,jint linkMiu)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 (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 *******************************************************************************/
nativeLlcpConnectionlessSocket_doClose(JNIEnv * e,jobject o)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 *******************************************************************************/
register_com_android_nfc_NativeLlcpConnectionlessSocket(JNIEnv * e)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