update the header for Doxygen
[platform/framework/native/bluetooth.git] / src / FNetBt_BluetoothSppInitiatorImpl.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012-2013 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 // @file        FNetBt_BluetoothSppInitiatorImpl.cpp
18 // @brief       This is the implementation file for the _BluetoothSppInitiatorImpl class.
19 //
20
21 #include <FOspConfig.h>
22 #include <FBaseUuId.h>
23 #include <FNetBtBluetoothTypes.h>
24 #include <FNetBtBluetoothDevice.h>
25 #include <FNetBtIBluetoothSppInitiatorEventListener.h>
26 #include <FBaseSysLog.h>
27 #include "FNetBt_BluetoothSppInitiatorEvent.h"
28 #include "FNetBt_BluetoothSppInitiatorEventArg.h"
29 #include "FNetBt_BluetoothGapSystemAdapter.h"
30 #include "FNetBt_BluetoothSppSystemAdapter.h"
31 #include "FNetBt_BluetoothSppInitiatorImpl.h"
32
33 using namespace std;
34 using namespace Tizen::Base;
35 using namespace Tizen::Base::Runtime;
36
37 namespace Tizen { namespace Net { namespace Bluetooth
38 {
39
40 _BluetoothSppInitiatorImpl::_BluetoothSppInitiatorImpl(void)
41         : __pGapAdapter(null)
42         , __pSppAdapter(null)
43         , __pEvent(null)
44         , __stateMutex()
45         , __currentState(_BT_SPP_INI_STATE_DISABLED)
46         , __pairingAddress()
47         , __pairingUuid()
48         , __socketFd(_BT_INVALID_SOCKET_FD)
49 {
50 }
51
52 _BluetoothSppInitiatorImpl::~_BluetoothSppInitiatorImpl(void)
53 {
54         if (__pSppAdapter != null)
55         {
56                 if ((__currentState == _BT_SPP_INI_STATE_BONDING)
57                         || (__currentState == _BT_SPP_INI_STATE_CONNECT_READY)
58                         || (__currentState == _BT_SPP_INI_STATE_CONNECTED))
59                 {
60                         (void) ProcessAsyncDisconnect();    // Ignores the result of this function.
61                 }
62         }
63
64         if (__pGapAdapter != null)
65         {
66                 __pGapAdapter->UnregisterManagerEventListener(*this);
67                 __pGapAdapter->UnregisterDeviceEventListener(*this);
68         }
69 }
70
71 result
72 _BluetoothSppInitiatorImpl::Construct(IBluetoothSppInitiatorEventListener& listener)
73 {
74         result r = E_SUCCESS;
75         std::unique_ptr<_BluetoothSppInitiatorEvent> pEvent;
76
77         r = __stateMutex.Create();
78         SysTryReturn(NID_NET_BT, r == E_SUCCESS, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to create the state mutex.");
79
80         r = __pairingAddress.Construct(_BT_ADDRESS_LENGTH);
81         SysTryReturn(NID_NET_BT, r == E_SUCCESS, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to construct the address for pairing.");
82
83         __pGapAdapter = _BluetoothGapSystemAdapter::GetInstance();
84         SysTryReturn(NID_NET_BT, __pGapAdapter != null, E_SYSTEM, E_SYSTEM,
85                                 "[E_SYSTEM] Failed to invoke _BluetoothGapSystemAdapter::GetInstance().");
86
87         __pSppAdapter = _BluetoothSppSystemAdapter::GetInstance();
88         SysTryReturn(NID_NET_BT, __pSppAdapter != null, E_SYSTEM, E_SYSTEM,
89                                 "[E_SYSTEM] Failed to invoke _BluetoothSppSystemAdapter::GetInstance().");
90
91         pEvent.reset(new (std::nothrow) _BluetoothSppInitiatorEvent());
92         SysTryReturn(NID_NET_BT, pEvent != null, r = E_OUT_OF_MEMORY, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
93         pEvent->Construct();
94         SysTryReturn(NID_NET_BT, r == E_SUCCESS, E_SYSTEM, E_SYSTEM, "[E_SYSTEM] Failed to construct the event.");
95         // add the IBluetoothSppInitiatorEventListener instance to a new created _BluetoothSppInitiatorEvent.
96         r = pEvent->AddListener(listener, true);
97         SysTryReturn(NID_NET_BT, r == E_SUCCESS, E_SYSTEM, E_SYSTEM,
98                         "[%s] Propagating. Failed to add the application listener for SPP Initiator", GetErrorMessage(r));
99
100         // registers this callback listener to the system adapter for activation/deactivation event
101         r = __pGapAdapter->RegisterManagerEventListener(*this, true);
102         SysTryReturn(NID_NET_BT, r == E_SUCCESS, E_SYSTEM, E_SYSTEM,
103                            "[E_SYSTEM] Failed to register the callback listener to _BluetoothGapSystemAdapter.");
104
105         // registers this callback listener to the system adapter for paired event
106         r = __pGapAdapter->RegisterDeviceEventListener(*this);
107         if (r != E_SUCCESS)
108         {
109                 __pGapAdapter->UnregisterManagerEventListener(*this);
110         }
111         SysTryReturn(NID_NET_BT, r == E_SUCCESS, E_SYSTEM, E_SYSTEM,
112                            "[E_SYSTEM] Failed to register the callback listener to _BluetoothGapSystemAdapter.");
113
114         // checks whether the Bluetooth is available
115         __stateMutex.Acquire();
116
117         if (__pGapAdapter->IsActivated() == true)
118         {
119                 __currentState = _BT_SPP_INI_STATE_IDLE;
120         }
121
122         __stateMutex.Release();
123
124         __pEvent = move(pEvent);
125
126         return E_SUCCESS;
127 }
128
129 result
130 _BluetoothSppInitiatorImpl::SendData(const Tizen::Base::ByteBuffer& buffer)
131 {
132         SysLog(NID_NET_BT, "EntryPoint, [CurrentState:%s]", GetStringOfCurrentState());
133
134         result r = E_FAILURE;
135
136         __stateMutex.Acquire();
137
138         switch (__currentState)
139         {
140         case _BT_SPP_INI_STATE_DISABLED:
141                 r = E_INVALID_STATE;
142                 break;
143
144         case _BT_SPP_INI_STATE_IDLE:
145         case _BT_SPP_INI_STATE_BONDING:         //TODO: this state should return E_INVALID_OPERATION. Versioning
146         case _BT_SPP_INI_STATE_CONNECT_READY:
147         case _BT_SPP_INI_STATE_REQ_CANCELING:   //TODO: this state should return E_INVALID_OPERATION. Versioning
148                 r = E_INVALID_OPERATION;
149                 break;
150
151         case _BT_SPP_INI_STATE_CONNECTED:
152                 if (buffer.GetRemaining() > 0)
153                 {
154                         r = __pSppAdapter->SendSocketData(__socketFd, buffer);
155                 }
156                 else
157                 {
158                         r = E_INVALID_ARG;
159                 }
160                 break;
161
162         default:
163                 r = E_FAILURE;
164                 break;
165         }
166
167         __stateMutex.Release();
168
169         if (r != E_SUCCESS)
170         {
171                 SysLogException(NID_NET_BT, r, "[%s] exception occurred on sending data.", GetErrorMessage(r));
172         }
173
174         SysLog(NID_NET_BT, "ExitPoint, [CurrentState:%s], [ActionResult:%s]", GetStringOfCurrentState(), GetErrorMessage(r));
175
176         return r;
177 }
178
179 result
180 _BluetoothSppInitiatorImpl::Connect(const BluetoothDevice& remoteDevice, const Tizen::Base::UuId& serviceUuid)
181 {
182         SysLog(NID_NET_BT, "EntryPoint, [CurrentState:%s]", GetStringOfCurrentState());
183
184         result r = E_FAILURE;
185
186         __stateMutex.Acquire();
187
188         switch (__currentState)
189         {
190         case _BT_SPP_INI_STATE_DISABLED:
191         case _BT_SPP_INI_STATE_REQ_CANCELING:
192                 r = E_INVALID_STATE;
193                 break;
194
195         case _BT_SPP_INI_STATE_IDLE:
196                 if (__pGapAdapter->IsPaired(*(remoteDevice.GetAddress())) == true)
197                 {
198                         r = __pSppAdapter->ConnectSocket(*(remoteDevice.GetAddress()), serviceUuid, *this);
199                         if (r == E_SUCCESS)
200                         {
201                                 __currentState = _BT_SPP_INI_STATE_CONNECT_READY;
202                         }
203                 }
204                 else
205                 {
206                         // start the pairing process
207                         if (__pGapAdapter->Pair(*(remoteDevice.GetAddress())) == E_SUCCESS)
208                         {
209                                 // copy the address of the pairing device to the local variable
210                                 __pairingAddress.SetArray(remoteDevice.GetAddress()->GetPointer(), 0, _BT_ADDRESS_LENGTH);
211                                 __pairingAddress.SetPosition(0);
212                                 __pairingUuid = serviceUuid;
213
214                                 r = E_SUCCESS;
215                                 __currentState = _BT_SPP_INI_STATE_BONDING;
216                         }
217                         else
218                         {
219                                 r = E_FAILURE;
220                         }
221                 }
222                 break;
223
224         case _BT_SPP_INI_STATE_BONDING:   //TODO: Versioning check
225         case _BT_SPP_INI_STATE_CONNECT_READY:
226                 r = E_IN_PROGRESS;
227                 break;
228
229         case _BT_SPP_INI_STATE_CONNECTED:
230                 r = E_ALREADY_CONNECTED;
231                 break;
232
233         default:
234                 r = E_FAILURE;
235                 break;
236         }
237
238         __stateMutex.Release();
239
240         if (r != E_SUCCESS)
241         {
242                 SysLogException(NID_NET_BT, r, "[%s] exception occurred on requesting a connection.", GetErrorMessage(r));
243         }
244
245         SysLog(NID_NET_BT, "ExitPoint, [CurrentState:%s], [ActionResult:%s]", GetStringOfCurrentState(), GetErrorMessage(r));
246
247         return r;
248 }
249
250 result
251 _BluetoothSppInitiatorImpl::Disconnect(void)
252 {
253         SysLog(NID_NET_BT, "EntryPoint, [CurrentState:%s]", GetStringOfCurrentState());
254
255         result r = E_FAILURE;
256
257         __stateMutex.Acquire();
258
259         switch (__currentState)
260         {
261         case _BT_SPP_INI_STATE_DISABLED:
262                 r = E_INVALID_STATE;
263                 break;
264
265         case _BT_SPP_INI_STATE_IDLE:
266                 r = E_INVALID_OPERATION;
267                 break;
268
269         case _BT_SPP_INI_STATE_BONDING:   //TODO: Versioning check
270                 if (__pGapAdapter->CancelPair() == E_SUCCESS)
271                 {
272                         r = E_SUCCESS;
273                         __currentState = _BT_SPP_INI_STATE_REQ_CANCELING;
274                 }
275                 // It will be changed to IDLE after receiving the OnBluetoothPaired event.
276                 break;
277
278         case _BT_SPP_INI_STATE_CONNECT_READY:
279                 // TODO: how does it cancel to request the connection? __socketFd is not determined at this time.
280                 r = ProcessAsyncDisconnect();
281                 if (r == E_SUCCESS)
282                 {
283                         __currentState = _BT_SPP_INI_STATE_REQ_CANCELING;
284                 }
285                 // It will be changed to IDLE after receiving the OnSppDisconnected event.
286                 break;
287
288         case _BT_SPP_INI_STATE_REQ_CANCELING:
289                 r = E_IN_PROGRESS;
290                 break;
291
292         case _BT_SPP_INI_STATE_CONNECTED:
293                 r = ProcessAsyncDisconnect();
294                 if (r == E_SUCCESS)
295                 {
296                         __currentState = _BT_SPP_INI_STATE_IDLE;
297                 }
298                 // It will be changed to IDLE after receiving the OnSppDisconnected event.
299                 break;
300
301         default:
302                 r = E_FAILURE;
303                 break;
304         }
305
306         __stateMutex.Release();
307
308         if (r != E_SUCCESS)
309         {
310                 SysLogException(NID_NET_BT, r, "[%s] exception occurred on disconnecting the connection.", GetErrorMessage(r));
311         }
312
313         SysLog(NID_NET_BT, "ExitPoint, [CurrentState:%s], [ActionResult:%s]", GetStringOfCurrentState(), GetErrorMessage(r));
314
315         return r;
316 }
317
318 void
319 _BluetoothSppInitiatorImpl::OnBluetoothActivated(result r)
320 {
321         SysLog(NID_NET_BT, "EntryPoint, [CurrentState:%s], [ActionResult:%s]", GetStringOfCurrentState(), GetErrorMessage(r));
322
323         __stateMutex.Acquire();
324
325         if ((__currentState == _BT_SPP_INI_STATE_DISABLED) && (r == E_SUCCESS))
326         {
327                 __currentState = _BT_SPP_INI_STATE_IDLE;
328         }
329         __stateMutex.Release();
330
331         SysLog(NID_NET_BT, "ExitPoint, [CurrentState:%s]", GetStringOfCurrentState());
332 }
333
334 void
335 _BluetoothSppInitiatorImpl::OnBluetoothDeactivated(result r)
336 {
337         SysLog(NID_NET_BT, "EntryPoint, [CurrentState:%s], [ActionResult:%s]", GetStringOfCurrentState(), GetErrorMessage(r));
338
339         __stateMutex.Acquire();
340
341         if (r == E_SUCCESS)
342         {
343                 __currentState = _BT_SPP_INI_STATE_DISABLED;
344         }
345
346         __stateMutex.Release();
347
348         SysLog(NID_NET_BT, "ExitPoint, [CurrentState:%s]", GetStringOfCurrentState());
349 }
350
351 void
352 _BluetoothSppInitiatorImpl::OnSocketConnectionResponded(int socketFd, result r)
353 {
354         SysLog(NID_NET_BT, "EntryPoint, [CurrentState:%s], [ActionResult:%s]", GetStringOfCurrentState(), GetErrorMessage(r));
355
356         bool isFired = false;
357
358         __stateMutex.Acquire();
359
360         if ((__currentState == _BT_SPP_INI_STATE_CONNECT_READY)
361                 || (__currentState == _BT_SPP_INI_STATE_REQ_CANCELING))
362         {
363                 if (r == E_SUCCESS)
364                 {
365                         __currentState = _BT_SPP_INI_STATE_CONNECTED;
366                         __socketFd = socketFd;
367                 }
368                 else
369                 {
370                         // including the cases as r == E_REJECTED or r == E_MAX_EXCEEDED
371                         // E_MAX_EXCEEDED is originated in the previous version.
372                         __currentState = _BT_SPP_INI_STATE_IDLE;
373                         SysLogException(NID_NET_BT, r, "[%s] exception occurred on the response of the SPP connect request.", GetErrorMessage(r));
374                 }
375
376                 isFired = true;
377         }
378         // ignore other cases
379
380         __stateMutex.Release();
381
382         if (isFired)
383         {
384                 _BluetoothSppInitiatorEventArg* pArg = new (std::nothrow) _BluetoothSppInitiatorEventArg(true, r);
385                 if (pArg == null)
386                 {
387                         SysLogException(NID_NET_BT, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
388                         isFired = false;
389                 }
390                 else
391                 {
392                         __pEvent->FireAsync(*pArg);
393                 }
394         }
395
396         SysLog(NID_NET_BT, "ExitPoint, [CurrentState:%s], [CONNECT_RESPONDED_Event:%s]",
397                                 GetStringOfCurrentState(), isFired ? "Fired" : "NotFired");
398 }
399
400 void
401 _BluetoothSppInitiatorImpl::OnSocketDisconnected(result r)
402 {
403         SysLog(NID_NET_BT, "EntryPoint, [CurrentState:%s], [ActionResult:%s]", GetStringOfCurrentState(), GetErrorMessage(r));
404
405         bool isFired = false;
406
407         __stateMutex.Acquire();
408
409         if (__currentState == _BT_SPP_INI_STATE_CONNECTED)
410         {
411                 if (r == E_SUCCESS)
412                 {
413                         __currentState = _BT_SPP_INI_STATE_IDLE;
414                         __socketFd = _BT_INVALID_SOCKET_FD;
415                         isFired = true;
416                 }
417         }
418         // ignore other cases
419
420         __stateMutex.Release();
421
422         if (isFired)
423         {
424                 _BluetoothSppInitiatorEventArg* pArg = new (std::nothrow) _BluetoothSppInitiatorEventArg(false, r);
425                 if (pArg == null)
426                 {
427                         SysLogException(NID_NET_BT, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
428                         isFired = false;
429                 }
430                 else
431                 {
432                         __pEvent->FireAsync(*pArg);
433                 }
434         }
435
436         SysLog(NID_NET_BT, "ExitPoint, [CurrentState:%s], [DISCONNECTED_Event:%s]",
437                                 GetStringOfCurrentState(), isFired ? "Fired" : "NotFired");
438 }
439
440 void
441 _BluetoothSppInitiatorImpl::OnSocketDataReceived(Tizen::Base::ByteBuffer& buffer)
442 {
443         SysLog(NID_NET_BT, "EntryPoint, [CurrentState:%s]", GetStringOfCurrentState());
444
445         bool isFired = false;
446
447         __stateMutex.Acquire();
448
449         if (__currentState == _BT_SPP_INI_STATE_CONNECTED)
450         {
451                 isFired = true;
452         }
453         // ignore other cases
454
455         __stateMutex.Release();
456
457         if (isFired)
458         {
459                 _BluetoothSppInitiatorEventArg* pArg = new (std::nothrow) _BluetoothSppInitiatorEventArg(buffer);
460                 if (pArg == null)
461                 {
462                         SysLogException(NID_NET_BT, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
463                         isFired = false;
464                 }
465                 else
466                 {
467                         // use Fire() instead of FireAsync() to improve the transfer rate.
468                         __pEvent->Fire(*pArg);
469                 }
470         }
471
472         SysLog(NID_NET_BT, "ExitPoint, [CurrentState:%s], [DATA_RECIEVED_Event:%s]",
473                                 GetStringOfCurrentState(), isFired ? "Fired" : "NotFired");
474 }
475
476 void
477 _BluetoothSppInitiatorImpl::OnBluetoothPaired(const BluetoothDevice* pPairedDevice, result r)
478 {
479         SysLog(NID_NET_BT, "EntryPoint, [CurrentState:%s], [ActionResult:%s]", GetStringOfCurrentState(), GetErrorMessage(r));
480
481         bool isFired = false;
482         result responseResult = E_SYSTEM;
483
484         __stateMutex.Acquire();
485
486         if (pPairedDevice->GetAddress()->Equals(__pairingAddress))
487         {
488                 if (__currentState == _BT_SPP_INI_STATE_BONDING)
489                 {
490                         if (r == E_SUCCESS)
491                         {
492                                 if (__pSppAdapter->ConnectSocket(__pairingAddress, __pairingUuid, *this) == E_SUCCESS)
493                                 {
494                                         __currentState = _BT_SPP_INI_STATE_CONNECT_READY;
495                                 }
496                                 else
497                                 {
498                                         // callback responded with E_SYSTEM
499                                         isFired = true;
500                                         __currentState = _BT_SPP_INI_STATE_IDLE;
501                                         responseResult = E_SYSTEM;
502                                 }
503                         }
504                         else
505                         {
506                                 // callback responded with r
507                                 isFired = true;
508                                 __currentState = _BT_SPP_INI_STATE_IDLE;
509                                 responseResult = r;
510                         }
511
512                         __pairingAddress.Clear();
513                 }
514                 else if (__currentState == _BT_SPP_INI_STATE_REQ_CANCELING)
515                 {
516                         // callback responded with E_SYSTEM or E_OPERATION_CANCELED
517                         isFired = true;
518                         __currentState = _BT_SPP_INI_STATE_IDLE;
519                         responseResult = E_SYSTEM;
520                 }
521                 // ignore other cases
522         }
523         // ignored otherwise
524
525         __stateMutex.Release();
526
527         if (isFired)
528         {
529                 _BluetoothSppInitiatorEventArg* pArg = new (std::nothrow) _BluetoothSppInitiatorEventArg(true, responseResult);
530                 if (pArg == null)
531                 {
532                         SysLogException(NID_NET_BT, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
533                         isFired = false;
534                 }
535                 else
536                 {
537                         __pEvent->FireAsync(*pArg);
538                 }
539         }
540
541         SysLog(NID_NET_BT, "ExitPoint, [CurrentState:%s], [CONNECT_RESPONDED_Event:%s]",
542                                 GetStringOfCurrentState(), isFired ? "Fired" : "NotFired");
543 }
544
545 result
546 _BluetoothSppInitiatorImpl::ProcessAsyncDisconnect(void)
547 {
548         result r = E_SUCCESS;
549
550         r = __pSppAdapter->DisconnectSocket(__socketFd);
551
552         // send a disconnected event here if the disconnect method is successful
553         // because the disconnect method of the underlying system is sync call. (transform sync into async)
554         if (r == E_SUCCESS)
555         {
556                 __socketFd = _BT_INVALID_SOCKET_FD;
557
558                 _BluetoothSppInitiatorEventArg* pArg = new (std::nothrow) _BluetoothSppInitiatorEventArg(false, r);
559                 if (pArg != null)
560                 {
561                         __pEvent->FireAsync(*pArg);
562                         SysLog(NID_NET_BT, "[DISCONNECTED_Event:Fired]");
563                 }
564         }
565
566         return r;
567 }
568
569 const char*
570 _BluetoothSppInitiatorImpl::GetStringOfCurrentState(void) const
571 {
572         const char* pStateString = null;
573
574         switch (__currentState)
575         {
576         case _BT_SPP_INI_STATE_DISABLED:
577                 pStateString = "DISABLED";
578                 break;
579
580         case _BT_SPP_INI_STATE_IDLE:
581                 pStateString = "IDLE";
582                 break;
583
584         case _BT_SPP_INI_STATE_BONDING:
585                 pStateString = "BONDING";
586                 break;
587
588         case _BT_SPP_INI_STATE_CONNECT_READY:
589                 pStateString = "CONNECT_READY";
590                 break;
591
592         case _BT_SPP_INI_STATE_REQ_CANCELING:
593                 pStateString = "REQ_CANCELING";
594                 break;
595
596         case _BT_SPP_INI_STATE_CONNECTED:
597                 pStateString = "CONNECTED";
598                 break;
599
600         default:
601                 pStateString = "Unknown";
602                 break;
603         }
604
605         return pStateString;
606 }
607
608 } } } // Tizen::Net::Bluetooth