1/*
2 * Copyright (C) 2010 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
20#include "com_android_nfc.h"
21
22namespace android {
23
24/*
25 * Callbacks
26 */
27
28static void nfc_jni_disconnect_callback(void*        pContext,
29                                               NFCSTATUS    status)
30{
31   struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
32   LOG_CALLBACK("nfc_jni_disconnect_callback", status);
33
34   /* Report the callback status and wake up the caller */
35   pCallbackData->status = status;
36   sem_post(&pCallbackData->sem);
37}
38
39
40static void nfc_jni_connect_callback(void* pContext, uint8_t nErrCode, NFCSTATUS status)
41{
42   struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
43   LOG_CALLBACK("nfc_jni_llcp_connect_callback", status);
44
45   if(status == NFCSTATUS_SUCCESS)
46   {
47      TRACE("Socket connected\n");
48   }
49   else
50   {
51      ALOGD("Socket not connected:");
52      switch(nErrCode)
53      {
54         case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE:
55            {
56               ALOGD("> SAP NOT ACTIVE\n");
57            }break;
58
59         case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND:
60            {
61               ALOGD("> SAP NOT FOUND\n");
62            }break;
63
64         case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED:
65            {
66               ALOGD("> CONNECT REJECTED\n");
67            }break;
68
69         case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED:
70            {
71               ALOGD("> CONNECT NOT ACCEPTED\n");
72            }break;
73
74         case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE:
75            {
76               ALOGD("> SOCKET NOT AVAILABLE\n");
77            }break;
78      }
79   }
80
81   /* Report the callback status and wake up the caller */
82   pCallbackData->status = status;
83   sem_post(&pCallbackData->sem);
84}
85
86
87
88
89static void nfc_jni_receive_callback(void* pContext, NFCSTATUS    status)
90{
91   struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
92   LOG_CALLBACK("nfc_jni_llcp_receive_callback", status);
93
94   /* Report the callback status and wake up the caller */
95   pCallbackData->status = status;
96   sem_post(&pCallbackData->sem);
97}
98
99static void nfc_jni_send_callback(void *pContext, NFCSTATUS status)
100{
101   struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
102   LOG_CALLBACK("nfc_jni_llcp_send_callback", status);
103
104   /* Report the callback status and wake up the caller */
105   pCallbackData->status = status;
106   sem_post(&pCallbackData->sem);
107}
108
109/*
110 * Methods
111 */
112static jboolean com_android_nfc_NativeLlcpSocket_doConnect(JNIEnv *e, jobject o, jint nSap)
113{
114   NFCSTATUS ret;
115   struct timespec ts;
116   phLibNfc_Handle hRemoteDevice;
117   phLibNfc_Handle hLlcpSocket;
118   struct nfc_jni_callback_data cb_data;
119   jboolean result = JNI_FALSE;
120
121   /* Retrieve handles */
122   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
123   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
124
125   /* Create the local semaphore */
126   if (!nfc_cb_data_init(&cb_data, NULL))
127   {
128      goto clean_and_return;
129   }
130
131   TRACE("phLibNfc_Llcp_Connect(%d)",nSap);
132   REENTRANCE_LOCK();
133   ret = phLibNfc_Llcp_Connect(hRemoteDevice,
134                               hLlcpSocket,
135                               nSap,
136                               nfc_jni_connect_callback,
137                               (void*)&cb_data);
138   REENTRANCE_UNLOCK();
139   if(ret != NFCSTATUS_PENDING)
140   {
141      ALOGE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret));
142      goto clean_and_return;
143   }
144   TRACE("phLibNfc_Llcp_Connect(%d) returned 0x%04x[%s]", nSap, ret, nfc_jni_get_status_name(ret));
145
146   /* Wait for callback response */
147   if(sem_wait(&cb_data.sem))
148   {
149      ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
150      goto clean_and_return;
151   }
152
153   if(cb_data.status != NFCSTATUS_SUCCESS)
154   {
155      ALOGW("LLCP Connect request failed");
156      goto clean_and_return;
157   }
158
159   result = JNI_TRUE;
160
161clean_and_return:
162   nfc_cb_data_deinit(&cb_data);
163   return result;
164}
165
166static jboolean com_android_nfc_NativeLlcpSocket_doConnectBy(JNIEnv *e, jobject o, jstring sn)
167{
168   NFCSTATUS ret;
169   struct timespec ts;
170   phNfc_sData_t serviceName = {NULL, 0};
171   phLibNfc_Handle hRemoteDevice;
172   phLibNfc_Handle hLlcpSocket;
173   struct nfc_jni_callback_data cb_data;
174   jboolean result = JNI_FALSE;
175
176   /* Retrieve handles */
177   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
178   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
179
180   /* Create the local semaphore */
181   if (!nfc_cb_data_init(&cb_data, NULL))
182   {
183      goto clean_and_return;
184   }
185
186   /* Service socket */
187   serviceName.buffer = (uint8_t*)e->GetStringUTFChars(sn, NULL);
188   serviceName.length = (uint32_t)e->GetStringUTFLength(sn);
189
190   TRACE("phLibNfc_Llcp_ConnectByUri()");
191   REENTRANCE_LOCK();
192   ret = phLibNfc_Llcp_ConnectByUri(hRemoteDevice,
193                                    hLlcpSocket,
194                                    &serviceName,
195                                    nfc_jni_connect_callback,
196                                    (void*)&cb_data);
197   REENTRANCE_UNLOCK();
198   if(ret != NFCSTATUS_PENDING)
199   {
200      ALOGE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
201      goto clean_and_return;
202   }
203   TRACE("phLibNfc_Llcp_ConnectByUri() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
204
205   /* Wait for callback response */
206   if(sem_wait(&cb_data.sem))
207   {
208      ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
209      goto clean_and_return;
210   }
211
212   if(cb_data.status != NFCSTATUS_SUCCESS)
213   {
214      goto clean_and_return;
215   }
216
217   result = JNI_TRUE;
218
219clean_and_return:
220   if (serviceName.buffer != NULL) {
221      e->ReleaseStringUTFChars(sn, (const char *)serviceName.buffer);
222   }
223   nfc_cb_data_deinit(&cb_data);
224   return result;
225}
226
227static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o)
228{
229   NFCSTATUS ret;
230   phLibNfc_Handle hLlcpSocket;
231
232   /* Retrieve socket handle */
233   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
234
235   TRACE("phLibNfc_Llcp_Close()");
236   REENTRANCE_LOCK();
237   ret = phLibNfc_Llcp_Close(hLlcpSocket);
238   REENTRANCE_UNLOCK();
239   if(ret != NFCSTATUS_SUCCESS)
240   {
241      ALOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
242      return FALSE;
243   }
244   TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
245   return TRUE;
246}
247
248static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray  data)
249{
250   NFCSTATUS ret;
251   struct timespec ts;
252   phLibNfc_Handle hRemoteDevice;
253   phLibNfc_Handle hLlcpSocket;
254   phNfc_sData_t sSendBuffer = {NULL, 0};
255   struct nfc_jni_callback_data cb_data;
256   jboolean result = JNI_FALSE;
257
258   /* Retrieve handles */
259   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
260   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
261
262   /* Create the local semaphore */
263   if (!nfc_cb_data_init(&cb_data, NULL))
264   {
265      goto clean_and_return;
266   }
267
268   sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL);
269   sSendBuffer.length = (uint32_t)e->GetArrayLength(data);
270
271   TRACE("phLibNfc_Llcp_Send()");
272   REENTRANCE_LOCK();
273   ret = phLibNfc_Llcp_Send(hRemoteDevice,
274                            hLlcpSocket,
275                            &sSendBuffer,
276                            nfc_jni_send_callback,
277                            (void*)&cb_data);
278   REENTRANCE_UNLOCK();
279   if(ret != NFCSTATUS_PENDING)
280   {
281      ALOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
282      goto clean_and_return;
283   }
284   TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
285
286   /* Wait for callback response */
287   if(sem_wait(&cb_data.sem))
288   {
289      ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
290      goto clean_and_return;
291   }
292
293   if(cb_data.status != NFCSTATUS_SUCCESS)
294   {
295       goto clean_and_return;
296   }
297
298   result = JNI_TRUE;
299
300clean_and_return:
301   if (sSendBuffer.buffer != NULL)
302   {
303      e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT);
304   }
305   nfc_cb_data_deinit(&cb_data);
306   return result;
307}
308
309static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray  buffer)
310{
311   NFCSTATUS ret;
312   struct timespec ts;
313   phLibNfc_Handle hRemoteDevice;
314   phLibNfc_Handle hLlcpSocket;
315   phNfc_sData_t sReceiveBuffer = {NULL, 0};
316   struct nfc_jni_callback_data cb_data;
317   jint result = -1;
318
319   /* Retrieve handles */
320   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
321   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
322
323   /* Create the local semaphore */
324   if (!nfc_cb_data_init(&cb_data, NULL))
325   {
326      goto clean_and_return;
327   }
328
329   sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL);
330   sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer);
331
332   TRACE("phLibNfc_Llcp_Recv()");
333   REENTRANCE_LOCK();
334   ret = phLibNfc_Llcp_Recv(hRemoteDevice,
335                            hLlcpSocket,
336                            &sReceiveBuffer,
337                            nfc_jni_receive_callback,
338                            (void*)&cb_data);
339   REENTRANCE_UNLOCK();
340   if(ret == NFCSTATUS_PENDING)
341   {
342      /* Wait for callback response */
343      if(sem_wait(&cb_data.sem))
344      {
345         ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
346         goto clean_and_return;
347      }
348
349      if(cb_data.status == NFCSTATUS_SUCCESS)
350      {
351         result = sReceiveBuffer.length;
352      }
353   }
354   else if (ret == NFCSTATUS_SUCCESS)
355   {
356      result = sReceiveBuffer.length;
357   }
358   else
359   {
360      /* Return status should be either SUCCESS or PENDING */
361      ALOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
362      goto clean_and_return;
363   }
364   TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
365
366clean_and_return:
367   if (sReceiveBuffer.buffer != NULL)
368   {
369      e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0);
370   }
371   nfc_cb_data_deinit(&cb_data);
372   return result;
373}
374
375static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o)
376{
377   NFCSTATUS ret;
378   phLibNfc_Handle hRemoteDevice;
379   phLibNfc_Handle hLlcpSocket;
380   phLibNfc_Llcp_sSocketOptions_t   remoteSocketOption;
381
382   /* Retrieve handles */
383   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
384   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
385
386   TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)");
387   REENTRANCE_LOCK();
388   ret  = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice,
389                                               hLlcpSocket,
390                                               &remoteSocketOption);
391   REENTRANCE_UNLOCK();
392   if(ret == NFCSTATUS_SUCCESS)
393   {
394      TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
395      return remoteSocketOption.miu;
396   }
397   else
398   {
399      ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
400      return 0;
401   }
402}
403
404static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o)
405{
406   NFCSTATUS ret;
407   phLibNfc_Handle hRemoteDevice;
408   phLibNfc_Handle hLlcpSocket;
409   phLibNfc_Llcp_sSocketOptions_t   remoteSocketOption;
410
411   /* Retrieve handles */
412   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
413   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
414
415   TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)");
416   REENTRANCE_LOCK();
417   ret  = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice,
418                                               hLlcpSocket,
419                                               &remoteSocketOption);
420   REENTRANCE_UNLOCK();
421   if(ret == NFCSTATUS_SUCCESS)
422   {
423      TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
424      return remoteSocketOption.rw;
425   }
426   else
427   {
428      ALOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
429      return 0;
430   }
431}
432
433
434/*
435 * JNI registration.
436 */
437static JNINativeMethod gMethods[] =
438{
439   {"doConnect", "(I)Z",
440      (void *)com_android_nfc_NativeLlcpSocket_doConnect},
441
442   {"doConnectBy", "(Ljava/lang/String;)Z",
443      (void *)com_android_nfc_NativeLlcpSocket_doConnectBy},
444
445   {"doClose", "()Z",
446      (void *)com_android_nfc_NativeLlcpSocket_doClose},
447
448   {"doSend", "([B)Z",
449      (void *)com_android_nfc_NativeLlcpSocket_doSend},
450
451   {"doReceive", "([B)I",
452      (void *)com_android_nfc_NativeLlcpSocket_doReceive},
453
454   {"doGetRemoteSocketMiu", "()I",
455      (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU},
456
457   {"doGetRemoteSocketRw", "()I",
458      (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW},
459};
460
461
462int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e)
463{
464   return jniRegisterNativeMethods(e,
465      "com/android/nfc/dhimpl/NativeLlcpSocket",gMethods, NELEM(gMethods));
466}
467
468} // namespace android
469