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      LOGD("Socket not connected:");
52      switch(nErrCode)
53      {
54         case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_ACTIVE:
55            {
56               LOGD("> SAP NOT ACTIVE\n");
57            }break;
58
59         case PHFRINFC_LLCP_DM_OPCODE_SAP_NOT_FOUND:
60            {
61               LOGD("> SAP NOT FOUND\n");
62            }break;
63
64         case PHFRINFC_LLCP_DM_OPCODE_CONNECT_REJECTED:
65            {
66               LOGD("> CONNECT REJECTED\n");
67            }break;
68
69         case PHFRINFC_LLCP_DM_OPCODE_CONNECT_NOT_ACCEPTED:
70            {
71               LOGD("> CONNECT NOT ACCEPTED\n");
72            }break;
73
74         case PHFRINFC_LLCP_DM_OPCODE_SOCKET_NOT_AVAILABLE:
75            {
76               LOGD("> 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      LOGE("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      LOGE("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      LOGW("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;
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      LOGE("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      LOGE("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   nfc_cb_data_deinit(&cb_data);
221   return result;
222}
223
224static jboolean com_android_nfc_NativeLlcpSocket_doClose(JNIEnv *e, jobject o)
225{
226   NFCSTATUS ret;
227   phLibNfc_Handle hLlcpSocket;
228
229   /* Retrieve socket handle */
230   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
231
232   TRACE("phLibNfc_Llcp_Close()");
233   REENTRANCE_LOCK();
234   ret = phLibNfc_Llcp_Close(hLlcpSocket);
235   REENTRANCE_UNLOCK();
236   if(ret != NFCSTATUS_SUCCESS)
237   {
238      LOGE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
239      return FALSE;
240   }
241   TRACE("phLibNfc_Llcp_Close() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
242   return TRUE;
243}
244
245static jboolean com_android_nfc_NativeLlcpSocket_doSend(JNIEnv *e, jobject o, jbyteArray  data)
246{
247   NFCSTATUS ret;
248   struct timespec ts;
249   phLibNfc_Handle hRemoteDevice;
250   phLibNfc_Handle hLlcpSocket;
251   phNfc_sData_t sSendBuffer = {NULL, 0};
252   struct nfc_jni_callback_data cb_data;
253   jboolean result = JNI_FALSE;
254
255   /* Retrieve handles */
256   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
257   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
258
259   /* Create the local semaphore */
260   if (!nfc_cb_data_init(&cb_data, NULL))
261   {
262      goto clean_and_return;
263   }
264
265   sSendBuffer.buffer = (uint8_t*)e->GetByteArrayElements(data, NULL);
266   sSendBuffer.length = (uint32_t)e->GetArrayLength(data);
267
268   TRACE("phLibNfc_Llcp_Send()");
269   REENTRANCE_LOCK();
270   ret = phLibNfc_Llcp_Send(hRemoteDevice,
271                            hLlcpSocket,
272                            &sSendBuffer,
273                            nfc_jni_send_callback,
274                            (void*)&cb_data);
275   REENTRANCE_UNLOCK();
276   if(ret != NFCSTATUS_PENDING)
277   {
278      LOGE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
279      goto clean_and_return;
280   }
281   TRACE("phLibNfc_Llcp_Send() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
282
283   /* Wait for callback response */
284   if(sem_wait(&cb_data.sem))
285   {
286      LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
287      goto clean_and_return;
288   }
289
290   if(cb_data.status != NFCSTATUS_SUCCESS)
291   {
292       goto clean_and_return;
293   }
294
295   result = JNI_TRUE;
296
297clean_and_return:
298   if (sSendBuffer.buffer != NULL)
299   {
300      e->ReleaseByteArrayElements(data, (jbyte*)sSendBuffer.buffer, JNI_ABORT);
301   }
302   nfc_cb_data_deinit(&cb_data);
303   return result;
304}
305
306static jint com_android_nfc_NativeLlcpSocket_doReceive(JNIEnv *e, jobject o, jbyteArray  buffer)
307{
308   NFCSTATUS ret;
309   struct timespec ts;
310   phLibNfc_Handle hRemoteDevice;
311   phLibNfc_Handle hLlcpSocket;
312   phNfc_sData_t sReceiveBuffer = {NULL, 0};
313   struct nfc_jni_callback_data cb_data;
314   jint result = -1;
315
316   /* Retrieve handles */
317   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
318   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
319
320   /* Create the local semaphore */
321   if (!nfc_cb_data_init(&cb_data, NULL))
322   {
323      goto clean_and_return;
324   }
325
326   sReceiveBuffer.buffer = (uint8_t*)e->GetByteArrayElements(buffer, NULL);
327   sReceiveBuffer.length = (uint32_t)e->GetArrayLength(buffer);
328
329   TRACE("phLibNfc_Llcp_Recv()");
330   REENTRANCE_LOCK();
331   ret = phLibNfc_Llcp_Recv(hRemoteDevice,
332                            hLlcpSocket,
333                            &sReceiveBuffer,
334                            nfc_jni_receive_callback,
335                            (void*)&cb_data);
336   REENTRANCE_UNLOCK();
337   if(ret == NFCSTATUS_PENDING)
338   {
339      /* Wait for callback response */
340      if(sem_wait(&cb_data.sem))
341      {
342         LOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
343         goto clean_and_return;
344      }
345
346      if(cb_data.status == NFCSTATUS_SUCCESS)
347      {
348         result = sReceiveBuffer.length;
349      }
350   }
351   else if (ret == NFCSTATUS_SUCCESS)
352   {
353      result = sReceiveBuffer.length;
354   }
355   else
356   {
357      /* Return status should be either SUCCESS or PENDING */
358      LOGE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
359      goto clean_and_return;
360   }
361   TRACE("phLibNfc_Llcp_Recv() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
362
363clean_and_return:
364   if (sReceiveBuffer.buffer != NULL)
365   {
366      e->ReleaseByteArrayElements(buffer, (jbyte*)sReceiveBuffer.buffer, 0);
367   }
368   nfc_cb_data_deinit(&cb_data);
369   return result;
370}
371
372static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU(JNIEnv *e, jobject o)
373{
374   NFCSTATUS ret;
375   phLibNfc_Handle hRemoteDevice;
376   phLibNfc_Handle hLlcpSocket;
377   phLibNfc_Llcp_sSocketOptions_t   remoteSocketOption;
378
379   /* Retrieve handles */
380   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
381   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
382
383   TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU)");
384   REENTRANCE_LOCK();
385   ret  = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice,
386                                               hLlcpSocket,
387                                               &remoteSocketOption);
388   REENTRANCE_UNLOCK();
389   if(ret == NFCSTATUS_SUCCESS)
390   {
391      TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
392      return remoteSocketOption.miu;
393   }
394   else
395   {
396      LOGW("phLibNfc_Llcp_SocketGetRemoteOptions(MIU) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
397      return 0;
398   }
399}
400
401static jint com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW(JNIEnv *e, jobject o)
402{
403   NFCSTATUS ret;
404   phLibNfc_Handle hRemoteDevice;
405   phLibNfc_Handle hLlcpSocket;
406   phLibNfc_Llcp_sSocketOptions_t   remoteSocketOption;
407
408   /* Retrieve handles */
409   hRemoteDevice = nfc_jni_get_p2p_device_handle(e,o);
410   hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
411
412   TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW)");
413   REENTRANCE_LOCK();
414   ret  = phLibNfc_Llcp_SocketGetRemoteOptions(hRemoteDevice,
415                                               hLlcpSocket,
416                                               &remoteSocketOption);
417   REENTRANCE_UNLOCK();
418   if(ret == NFCSTATUS_SUCCESS)
419   {
420      TRACE("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
421      return remoteSocketOption.rw;
422   }
423   else
424   {
425      LOGW("phLibNfc_Llcp_SocketGetRemoteOptions(RW) returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
426      return 0;
427   }
428}
429
430
431/*
432 * JNI registration.
433 */
434static JNINativeMethod gMethods[] =
435{
436   {"doConnect", "(I)Z",
437      (void *)com_android_nfc_NativeLlcpSocket_doConnect},
438
439   {"doConnectBy", "(Ljava/lang/String;)Z",
440      (void *)com_android_nfc_NativeLlcpSocket_doConnectBy},
441
442   {"doClose", "()Z",
443      (void *)com_android_nfc_NativeLlcpSocket_doClose},
444
445   {"doSend", "([B)Z",
446      (void *)com_android_nfc_NativeLlcpSocket_doSend},
447
448   {"doReceive", "([B)I",
449      (void *)com_android_nfc_NativeLlcpSocket_doReceive},
450
451   {"doGetRemoteSocketMiu", "()I",
452      (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketMIU},
453
454   {"doGetRemoteSocketRw", "()I",
455      (void *)com_android_nfc_NativeLlcpSocket_doGetRemoteSocketRW},
456};
457
458
459int register_com_android_nfc_NativeLlcpSocket(JNIEnv *e)
460{
461   return jniRegisterNativeMethods(e,
462      "com/android/nfc/nxp/NativeLlcpSocket",gMethods, NELEM(gMethods));
463}
464
465} // namespace android
466