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