Release 4.0.0-preview1-00051
[platform/core/csapi/tizenfx.git] / src / Tizen.Network.Bluetooth / Tizen.Network.Bluetooth / BluetoothSocket.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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 using System;
18 using System.Collections.Generic;
19 using System.Runtime.InteropServices;
20
21 namespace Tizen.Network.Bluetooth
22 {
23     /// <summary>
24     /// The IBluetoothServerSocket interface handles the server socket operations.
25     /// </summary>
26     public interface IBluetoothServerSocket
27     {
28         event EventHandler<SocketDataReceivedEventArgs> DataReceived;
29         event EventHandler<SocketConnectionStateChangedEventArgs> ConnectionStateChanged;
30         int SendData(string data);
31     }
32
33     /// <summary>
34     /// The IBluetoothClientSocket interface handles the client socket operations.
35     /// </summary>
36     public interface IBluetoothClientSocket : IBluetoothServerSocket
37     {
38         void Connect();
39         void Disconnect();
40     }
41
42     internal class BluetoothSocket : IBluetoothClientSocket, IDisposable
43     {
44         private event EventHandler<SocketDataReceivedEventArgs> _dataReceived;
45         private event EventHandler<SocketConnectionStateChangedEventArgs> _connectionStateChanged;
46         private Interop.Bluetooth.DataReceivedCallback _dataReceivedCallback;
47         private Interop.Bluetooth.SocketConnectionStateChangedCallback _connectionStateChangedCallback;
48         private bool disposed = false;
49         internal int connectedSocket;
50         internal string remoteAddress;
51         internal string serviceUuid;
52
53         /// <summary>
54         /// This event occurs when the socket server receives data from the client.
55         /// </summary>
56         /// <exception cref="System.InvalidOperationException">Thrown when the Bluetooth is not enabled
57         /// or when the register data received callback fails.</exception>
58         public event EventHandler<SocketDataReceivedEventArgs> DataReceived
59         {
60             add
61             {
62                 if (_dataReceived == null)
63                 {
64                     RegisterDataReceivedEvent();
65                 }
66                 _dataReceived += value;
67             }
68             remove
69             {
70                 _dataReceived -= value;
71                 if (_dataReceived == null)
72                 {
73                     UnregisterDataReceivedEvent();
74                 }
75             }
76         }
77
78         /// <summary>
79         /// This event occurs when the connection state between two devices is changed.
80         /// </summary>
81         /// <exception cref="System.InvalidOperationException">Thrown when the Bluetooth is not enabled
82         /// or when the register connection changed callback fails.</exception>
83         public event EventHandler<SocketConnectionStateChangedEventArgs> ConnectionStateChanged
84         {
85             add
86             {
87                 if (_connectionStateChanged == null)
88                 {
89                     RegisterConnectionStateChangedEvent();
90                 }
91                 _connectionStateChanged += value;
92             }
93             remove
94             {
95                 _connectionStateChanged -= value;
96                 if (_connectionStateChanged == null)
97                 {
98                     UnregisterConnectionStateChangedEvent();
99                 }
100             }
101         }
102
103         private void RegisterDataReceivedEvent()
104         {
105             _dataReceivedCallback = (ref SocketDataStruct socketData, IntPtr userData) =>
106             {
107                 Log.Info(Globals.LogTag, "DataReceivedCallback is called");
108                 if (_dataReceived != null)
109                 {
110                     GCHandle handle2 = (GCHandle) userData;
111                     _dataReceived(handle2.Target as IBluetoothServerSocket, new SocketDataReceivedEventArgs(BluetoothUtils.ConvertStructToSocketData(socketData)));
112                 }
113             };
114             GCHandle handle1 = GCHandle.Alloc (this);
115             IntPtr uData = (IntPtr) handle1;
116             int ret = Interop.Bluetooth.SetDataReceivedCallback(_dataReceivedCallback, uData);
117             if (ret != (int)BluetoothError.None)
118             {
119                 Log.Error(Globals.LogTag, "Failed to set data received callback, Error - " + (BluetoothError)ret);
120                 BluetoothErrorFactory.ThrowBluetoothException(ret);
121             }
122         }
123
124         private void UnregisterDataReceivedEvent()
125         {
126             int ret = Interop.Bluetooth.UnsetDataReceivedCallback();
127             if (ret != (int)BluetoothError.None)
128             {
129                 Log.Error(Globals.LogTag, "Failed to unset data received callback, Error - " + (BluetoothError)ret);
130                 BluetoothErrorFactory.ThrowBluetoothException(ret);
131             }
132         }
133
134         private void RegisterConnectionStateChangedEvent()
135         {
136             _connectionStateChangedCallback = (int result, BluetoothSocketState connectionState, ref SocketConnectionStruct socketConnection, IntPtr userData) =>
137             {
138                 Log.Info(Globals.LogTag, "ConnectionStateChangedCallback is called");
139                 if (_connectionStateChanged != null)
140                 {
141                     connectedSocket = socketConnection.SocketFd;
142                     GCHandle handle2 = (GCHandle) userData;
143                     _connectionStateChanged(handle2.Target as IBluetoothServerSocket, new SocketConnectionStateChangedEventArgs((BluetoothError)result, connectionState, BluetoothUtils.ConvertStructToSocketConnection(socketConnection)));
144                 }
145             };
146             GCHandle handle1 = GCHandle.Alloc(this);
147             IntPtr data = (IntPtr) handle1;
148             int ret = Interop.Bluetooth.SetConnectionStateChangedCallback(_connectionStateChangedCallback, data);
149             if (ret != (int)BluetoothError.None)
150             {
151                 Log.Error(Globals.LogTag, "Failed to set connection state changed callback, Error - " + (BluetoothError)ret);
152                 BluetoothErrorFactory.ThrowBluetoothException(ret);
153             }
154         }
155
156         private void UnregisterConnectionStateChangedEvent()
157         {
158             int ret = Interop.Bluetooth.UnsetSocketConnectionStateChangedCallback();
159             if (ret != (int)BluetoothError.None)
160             {
161                 Log.Error(Globals.LogTag, "Failed to unset connection state changed callback, Error - " + (BluetoothError)ret);
162                 BluetoothErrorFactory.ThrowBluetoothException(ret);
163             }
164         }
165
166         /// <summary>
167         /// Connects to a specific RFCOMM based service on a remote Bluetooth device UUID.
168         /// </summary>
169         /// <remarks>
170         /// The bluetooth must be enabled, discoverable with StartDiscovery(), and bonded with the remote device using CreateBond(). The ConnectionStateChanged event is raised once this API is called.
171         /// </remarks>
172         /// <param name="address">The address of the remote Bluetooth device.</param>
173         /// <param name="serviceUuid">The UUID of the service provided by the remote Bluetooth device.</param>
174         /// <exception cref="System.InvalidOperationException">Thrown when the Bluetooth is not enabled
175         /// or when the connect socket attempt to remote device fails, or when the service UUID is not supported by the remote device.</exception>
176         void IBluetoothClientSocket.Connect()
177         {
178             int ret = Interop.Bluetooth.ConnectSocket(remoteAddress, serviceUuid);
179             if (ret != (int)BluetoothError.None)
180             {
181                 Log.Error(Globals.LogTag, "Failed to connect to socket, Error - " + (BluetoothError)ret);
182                 BluetoothErrorFactory.ThrowBluetoothException(ret);
183             }
184         }
185
186         /// <summary>
187         /// Disconnects the RFCOMM connection with the given file descriptor of the conneted socket.
188         /// </summary>
189         /// <remarks>
190         /// The connection must be established.
191         /// </remarks>
192         /// <param name="socketFd">The file descriptor of the socket to close.</param>
193         /// <exception cref="System.InvalidOperationException">Thrown when the Bluetooth is not enabled
194         /// or when the socket disconnect to remote device fails.</exception>
195         void IBluetoothClientSocket.Disconnect()
196         {
197             int ret = Interop.Bluetooth.DisconnectSocket(connectedSocket);
198             if (ret != (int)BluetoothError.None)
199             {
200                 Log.Error(Globals.LogTag, "Failed to disconnect socket, Error - " + (BluetoothError)ret);
201                 BluetoothErrorFactory.ThrowBluetoothException(ret);
202             }
203         }
204
205         /// <summary>
206         /// Sends data to the connected device.
207         /// </summary>
208         /// <returns>The number of bytes written (zero indicates nothing was written).</returns>
209         /// <remarks>
210         /// The connection must be established.
211         /// </remarks>
212         /// <param name="socketFd">The file descriptor of the connected socket.</param>
213         /// <param name="data">The data to be sent.</param>
214         /// <exception cref="System.InvalidOperationException">Thrown when the Bluetooth is not enabled
215         /// or when the remote device is not connected, or the send data procedure fails.</exception>
216         public int SendData(string data)
217         {
218             int ret = Interop.Bluetooth.SendData(connectedSocket, data, data.Length);
219             if (ret < 0)
220             {
221                 Log.Error(Globals.LogTag, "Failed to send data, Error - " + (BluetoothError)ret);
222                 BluetoothErrorFactory.ThrowBluetoothException(ret);
223             }
224             return ret;
225         }
226
227         ~BluetoothSocket()
228         {
229             Dispose(false);
230         }
231
232         public void Dispose()
233         {
234             Dispose(true);
235             GC.SuppressFinalize(this);
236         }
237
238         private void Dispose(bool disposing)
239         {
240             if (disposed)
241                 return;
242
243             if (disposing)
244             {
245                 // Free managed objects.
246             }
247             //Free unmanaged objects
248             RemoveRegisteredEvents();
249             disposed = true;
250         }
251
252         private void RemoveRegisteredEvents()
253         {
254             //unregister all remaining events when this object is released.
255             if (_dataReceived != null)
256             {
257                 UnregisterDataReceivedEvent();
258             }
259             if (_connectionStateChanged != null)
260             {
261                 UnregisterConnectionStateChangedEvent();
262             }
263         }
264     }
265 }