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 #include <ScopedLocalRef.h>
20
21 #include "com_android_nfc.h"
22
23 namespace android {
24
25 extern void nfc_jni_llcp_transport_socket_err_callback(void* pContext,
26 uint8_t nErrCode);
27 /*
28 * Callbacks
29 */
nfc_jni_llcp_accept_socket_callback(void * pContext,NFCSTATUS status)30 static void nfc_jni_llcp_accept_socket_callback(void* pContext,
31 NFCSTATUS status)
32 {
33 struct nfc_jni_callback_data * pCallbackData = (struct nfc_jni_callback_data *) pContext;
34 LOG_CALLBACK("nfc_jni_llcp_accept_socket_callback", status);
35
36 /* Report the callback status and wake up the caller */
37 pCallbackData->status = status;
38 sem_post(&pCallbackData->sem);
39 }
40
41
42 /*
43 * Utils
44 */
45
getIncomingSocket(nfc_jni_native_monitor_t * pMonitor,phLibNfc_Handle hServerSocket)46 static phLibNfc_Handle getIncomingSocket(nfc_jni_native_monitor_t * pMonitor,
47 phLibNfc_Handle hServerSocket)
48 {
49 nfc_jni_listen_data_t * pListenData;
50 phLibNfc_Handle pIncomingSocket = (phLibNfc_Handle)NULL;
51
52 /* Look for a pending incoming connection on the current server */
53 LIST_FOREACH(pListenData, &pMonitor->incoming_socket_head, entries)
54 {
55 if (pListenData->pServerSocket == hServerSocket)
56 {
57 pIncomingSocket = pListenData->pIncomingSocket;
58 LIST_REMOVE(pListenData, entries);
59 free(pListenData);
60 break;
61 }
62 }
63
64 return pIncomingSocket;
65 }
66
67 /*
68 * Methods
69 */
com_NativeLlcpServiceSocket_doAccept(JNIEnv * e,jobject o,jint miu,jint rw,jint linearBufferLength)70 static jobject com_NativeLlcpServiceSocket_doAccept(JNIEnv *e, jobject o, jint miu, jint rw, jint linearBufferLength)
71 {
72 NFCSTATUS ret = NFCSTATUS_SUCCESS;
73 struct timespec ts;
74 phLibNfc_Llcp_sSocketOptions_t sOptions;
75 phNfc_sData_t sWorkingBuffer;
76 jfieldID f;
77 ScopedLocalRef<jclass> clsNativeLlcpSocket(e, NULL);
78 jobject clientSocket = NULL;
79 struct nfc_jni_callback_data cb_data;
80 phLibNfc_Handle hIncomingSocket, hServerSocket;
81 nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor();
82
83 hIncomingSocket = (phLibNfc_Handle)NULL;
84
85 /* Create the local semaphore */
86 if (!nfc_cb_data_init(&cb_data, NULL))
87 {
88 goto clean_and_return;
89 }
90
91 /* Get server socket */
92 hServerSocket = nfc_jni_get_nfc_socket_handle(e,o);
93
94 /* Set socket options with the socket options of the service */
95 sOptions.miu = miu;
96 sOptions.rw = rw;
97
98 /* Allocate Working buffer length */
99 sWorkingBuffer.buffer = (uint8_t*)malloc((miu*rw)+miu+linearBufferLength);
100 sWorkingBuffer.length = (miu*rw)+ miu + linearBufferLength;
101
102 while(cb_data.status != NFCSTATUS_SUCCESS)
103 {
104 /* Wait for tag Notification */
105 pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
106 while ((hIncomingSocket = getIncomingSocket(pMonitor, hServerSocket)) == (phLibNfc_Handle)NULL) {
107 pthread_cond_wait(&pMonitor->incoming_socket_cond, &pMonitor->incoming_socket_mutex);
108 }
109 pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);
110
111 /* Accept the incomming socket */
112 TRACE("phLibNfc_Llcp_Accept()");
113 REENTRANCE_LOCK();
114 ret = phLibNfc_Llcp_Accept( hIncomingSocket,
115 &sOptions,
116 &sWorkingBuffer,
117 nfc_jni_llcp_transport_socket_err_callback,
118 nfc_jni_llcp_accept_socket_callback,
119 (void*)&cb_data);
120 REENTRANCE_UNLOCK();
121 if(ret != NFCSTATUS_PENDING)
122 {
123 // NOTE: This may happen if link went down since incoming socket detected, then
124 // just drop it and start a new accept loop.
125 ALOGD("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
126 continue;
127 }
128 TRACE("phLibNfc_Llcp_Accept() returned 0x%04x[%s]", ret, nfc_jni_get_status_name(ret));
129
130 /* Wait for callback response */
131 if(sem_wait(&cb_data.sem))
132 {
133 ALOGE("Failed to wait for semaphore (errno=0x%08x)", errno);
134 goto clean_and_return;
135 }
136
137 if(cb_data.status != NFCSTATUS_SUCCESS)
138 {
139 /* NOTE: Do not generate an error if the accept failed to avoid error in server application */
140 ALOGD("Failed to accept incoming socket 0x%04x[%s]", cb_data.status, nfc_jni_get_status_name(cb_data.status));
141 }
142 }
143
144 /* Create new LlcpSocket object */
145 if(nfc_jni_cache_object(e,"com/android/nfc/dhimpl/NativeLlcpSocket",&(clientSocket)) == -1)
146 {
147 ALOGD("LLCP Socket creation error");
148 goto clean_and_return;
149 }
150
151 /* Get NativeConnectionOriented class object */
152 clsNativeLlcpSocket.reset(e->GetObjectClass(clientSocket));
153 if(e->ExceptionCheck())
154 {
155 ALOGD("LLCP Socket get class object error");
156 goto clean_and_return;
157 }
158
159 /* Set socket handle */
160 f = e->GetFieldID(clsNativeLlcpSocket.get(), "mHandle", "I");
161 e->SetIntField(clientSocket, f,(jint)hIncomingSocket);
162
163 /* Set socket MIU */
164 f = e->GetFieldID(clsNativeLlcpSocket.get(), "mLocalMiu", "I");
165 e->SetIntField(clientSocket, f,(jint)miu);
166
167 /* Set socket RW */
168 f = e->GetFieldID(clsNativeLlcpSocket.get(), "mLocalRw", "I");
169 e->SetIntField(clientSocket, f,(jint)rw);
170
171 TRACE("socket handle 0x%02x: MIU = %d, RW = %d\n",hIncomingSocket, miu, rw);
172
173 clean_and_return:
174 nfc_cb_data_deinit(&cb_data);
175 return clientSocket;
176 }
177
com_NativeLlcpServiceSocket_doClose(JNIEnv * e,jobject o)178 static jboolean com_NativeLlcpServiceSocket_doClose(JNIEnv *e, jobject o)
179 {
180 NFCSTATUS ret;
181 phLibNfc_Handle hLlcpSocket;
182 nfc_jni_native_monitor_t * pMonitor = nfc_jni_get_monitor();
183
184 TRACE("Close Service socket");
185
186 /* Retrieve socket handle */
187 hLlcpSocket = nfc_jni_get_nfc_socket_handle(e,o);
188
189 pthread_mutex_lock(&pMonitor->incoming_socket_mutex);
190 /* TODO: implement accept abort */
191 pthread_cond_broadcast(&pMonitor->incoming_socket_cond);
192 pthread_mutex_unlock(&pMonitor->incoming_socket_mutex);
193
194 REENTRANCE_LOCK();
195 ret = phLibNfc_Llcp_Close(hLlcpSocket);
196 REENTRANCE_UNLOCK();
197 if(ret == NFCSTATUS_SUCCESS)
198 {
199 TRACE("Close Service socket OK");
200 return TRUE;
201 }
202 else
203 {
204 ALOGD("Close Service socket KO");
205 return FALSE;
206 }
207 }
208
209
210 /*
211 * JNI registration.
212 */
213 static JNINativeMethod gMethods[] =
214 {
215 {"doAccept", "(III)Lcom/android/nfc/dhimpl/NativeLlcpSocket;",
216 (void *)com_NativeLlcpServiceSocket_doAccept},
217
218 {"doClose", "()Z",
219 (void *)com_NativeLlcpServiceSocket_doClose},
220 };
221
222
register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv * e)223 int register_com_android_nfc_NativeLlcpServiceSocket(JNIEnv *e)
224 {
225 return jniRegisterNativeMethods(e,
226 "com/android/nfc/dhimpl/NativeLlcpServiceSocket",
227 gMethods, NELEM(gMethods));
228 }
229
230 } // namespace android
231