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