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>
26extern "C"
27{
28    #include "nfa_api.h"
29    #include "nfa_p2p_api.h"
30}
31
32
33namespace android
34{
35
36
37/*****************************************************************************
38**
39** private variables and functions
40**
41*****************************************************************************/
42static sem_t        sConnlessRecvSem;
43static jboolean     sConnlessRecvWaitingForData = JNI_FALSE;
44static uint8_t*     sConnlessRecvBuf = NULL;
45static uint32_t     sConnlessRecvLen = 0;
46static 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*******************************************************************************/
62static 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*******************************************************************************/
103void 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*******************************************************************************/
134static 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*******************************************************************************/
156void 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*******************************************************************************/
174static 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
241TheEnd: // 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*******************************************************************************/
262static 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*****************************************************************************/
285static 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*******************************************************************************/
303int register_com_android_nfc_NativeLlcpConnectionlessSocket (JNIEnv *e)
304{
305    return jniRegisterNativeMethods (e, gNativeLlcpConnectionlessSocketClassName, gMethods, NELEM(gMethods));
306}
307
308
309} // android namespace
310