[MessagePort] Modify MessagePort, modify Bundle's handle
[platform/core/csapi/tizenfx.git] / Tizen.Applications / Tizen.Applications.MessagePort / MessagePort.cs
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Runtime.InteropServices;
6 using System.Text;
7 using System.Threading.Tasks;
8 using Tizen.Internals;
9
10 namespace Tizen.Applications.MessagePort
11 {
12     /// <summary>
13     /// The Message Port API provides functions to send and receive messages between applications.
14     /// </summary>
15     /// <remarks>
16     /// The Message Port API provides functions for passing messages between applications. An application should register its own local port to receive messages from remote applications.
17     /// If a remote application sends a message, the registered callback function of the local port is called.
18     /// The trusted message-port API allows communications between applications that are signed by the same developer(author) certificate.
19     /// </remarks>
20     public class MessagePort
21     {
22         private static Dictionary<MessagePort, int> s_portMap = new Dictionary<MessagePort, int>();
23
24         /// <summary>
25         /// Constructor
26         /// </summary>
27         /// <param name="portName">The name of the local message port</param>
28         /// <param name="trusted">If true is the trusted message port of application, otherwise false</param>
29         public MessagePort(string portName, bool trusted)
30         {
31             _portName = portName;
32             _trusted = trusted;
33         }
34
35         ~MessagePort()
36         {
37             if (_listening)
38             {
39                 StopListening();
40             }
41         }
42
43         /// <summary>
44         /// Called when a message is received.
45         /// </summary>
46         public event EventHandler<MessageReceivedEventArgs> MessageReceived;
47
48         private enum MessagePortError
49         {
50             None = Internals.Errors.ErrorCode.None,
51             IOError = Internals.Errors.ErrorCode.IoError,
52             OutOfMemory = Internals.Errors.ErrorCode.OutOfMemory,
53             InvalidParameter = Internals.Errors.ErrorCode.InvalidParameter,
54             PortNotFound = -0x01130000 | 0x01,
55             CertificateNotMatch = -0x01130000 | 0x02,
56             MaxExceeded = -0x01130000 | 0x03,
57             ResourceUnavailable = -0x01130000 | 0x04
58         }
59
60         /// <summary>
61         /// The name of the local message port
62         /// </summary>
63         public string PortName
64         {
65             get
66             {
67                 return _portName;
68             }
69         }
70         /// <summary>
71         /// If true the message port is a trusted port, otherwise false it is not
72         /// </summary>
73         public bool Trusted
74         {
75             get
76             {
77                 return _trusted;
78             }
79         }
80
81         /// <summary>
82         /// If true the message port is listening, otherwise false it is not
83         /// </summary>
84         public bool Listening
85         {
86             get
87             {
88                 return _listening;
89             }
90         }
91
92         /// <summary>
93         /// The local message port ID
94         /// </summary>
95         private int _portId = 0;
96
97         /// <summary>
98         /// The name of the local message port
99         /// </summary>
100         private string _portName = null;
101
102         /// <summary>
103         /// If true the message port is a trusted port, otherwise false it is not
104         /// </summary>
105         private bool _trusted = false;
106
107         /// <summary>
108         /// If true the message port is listening, otherwise false it is not
109         /// </summary>
110         private bool _listening = false;
111
112         private Interop.MessagePort.message_port_message_cb _messageCallBack;
113
114         /// <summary>
115         /// Register the local message port.
116         /// </summary>
117         public void Listen()
118         {
119             if (!s_portMap.ContainsKey(this))
120             {
121                 _messageCallBack = (int localPortId, string remoteAppId, string remotePortName, bool trusted, IntPtr message, IntPtr userData) =>
122                 {
123                     Bundle bundle = new Bundle(message);
124                     MessageReceivedEventArgs args;
125
126                     if (remotePortName != null)
127                     {
128                         args = new MessageReceivedEventArgs(bundle, remoteAppId, remotePortName, trusted);
129                     }
130                     else
131                     {
132                         args = new MessageReceivedEventArgs(bundle);
133                     }
134
135                     RaiseMessageReceivedEvent(MessageReceived, args);
136                 };
137
138                 if (_trusted)
139                 {
140                     _portId = Interop.MessagePort.RegisterTrustedPort(_portName, _messageCallBack, IntPtr.Zero);
141                 }
142                 else
143                 {
144                     _portId = Interop.MessagePort.RegisterPort(_portName, _messageCallBack, IntPtr.Zero);
145                 }
146
147                 if(_portId > 0)
148                 {
149                     s_portMap.Add(this, 1);
150                     _listening = true;
151                 }
152                 else
153                 {
154                     switch ((MessagePortError)_portId)
155                     {
156                         case MessagePortError.IOError: throw new IOException("I/O Error");
157                         case MessagePortError.OutOfMemory: throw new InvalidOperationException("Out of memory");
158                         case MessagePortError.InvalidParameter: throw new ArgumentException("Invalid parameter");
159                     }
160                 }
161             }
162             else
163             {
164                 throw new ArgumentException("Already listening");
165             }
166         }
167
168         /// <summary>
169         /// Unregisters the local message port.
170         /// </summary>
171         public void StopListening()
172         {
173             if (_listening)
174             {
175                 int ret;
176                 if (_trusted)
177                 {
178                     ret = Interop.MessagePort.UnregisterTrustedPort(_portId);
179                 }
180                 else
181                 {
182                     ret = Interop.MessagePort.UnregisterPort(_portId);
183                 }
184
185                 if (ret == 0)
186                 {
187                     s_portMap.Remove(this);
188                     _portId = 0;
189                     _listening = false;
190                 }
191                 else
192                 {
193                     switch ((MessagePortError)ret)
194                     {
195                         case MessagePortError.IOError: throw new IOException("I/O Error");
196                         case MessagePortError.OutOfMemory: throw new InvalidOperationException("Out of memory");
197                         case MessagePortError.InvalidParameter: throw new ArgumentException("Invalid parameter");
198                         case MessagePortError.PortNotFound: throw new ArgumentNullException("Port not found");
199                     }
200                 }
201             }
202             else
203             {
204                 throw new InvalidOperationException("Already stopped");
205             }
206         }
207
208         /// <summary>
209         /// Sends a message to the message port of a remote application.
210         /// </summary>
211         /// <param name="message">The message to be passed to the remote application, the recommended message size is under 4KB</param>
212         /// <param name="remoteAppId">The ID of the remote application</param>
213         /// <param name="remotePortName">The name of the remote message port</param>
214         /// <param name="trusted">If true the trusted message port of remote application otherwise false</param>
215         public void Send(Bundle message, string remoteAppId, string remotePortName, bool trusted=false)
216         {
217             if (_listening)
218             {
219                 int ret;
220                 if (trusted)
221                 {
222                     ret = Interop.MessagePort.SendTrustedMessageWithLocalPort(remoteAppId, remotePortName, message.Handle, _portId);
223                 }
224                 else
225                 {
226                     ret = Interop.MessagePort.SendMessageWithLocalPort(remoteAppId, remotePortName, message.Handle, _portId);
227                 }
228                 if (ret != 0)
229                 {
230                     switch ((MessagePortError)ret)
231                     {
232                         case MessagePortError.IOError: throw new IOException("I/O Error");
233                         case MessagePortError.InvalidParameter: throw new ArgumentException("Invalid parameter");
234                         case MessagePortError.OutOfMemory: throw new InvalidOperationException("Out of memory");
235                         case MessagePortError.PortNotFound: throw new ArgumentNullException("Port not found");
236                         case MessagePortError.CertificateNotMatch: throw new ArgumentException("Certification not match");
237                         case MessagePortError.MaxExceeded: throw new ArgumentOutOfRangeException("Max(4KB) exceeded");
238                         case MessagePortError.ResourceUnavailable: throw new ArgumentNullException("Resource unavailable");
239                     }
240                 }
241             }
242             else
243             {
244                 throw new InvalidOperationException("Need listening");
245             }
246         }
247
248         /// <summary>
249         /// Override GetHashCode
250         /// </summary>
251         /// <returns></returns>
252         public override int GetHashCode()
253         {
254             int hash = 0;
255             if (_portName != null)
256             {
257                 hash ^= _portName.GetHashCode();
258             }
259             hash ^= _trusted.GetHashCode();
260             return hash;
261         }
262
263         /// <summary>
264         /// Override Equals
265         /// </summary>
266         /// <param name="obj"></param>
267         /// <returns></returns>
268         public override bool Equals(object obj)
269         {
270             MessagePort p = obj as MessagePort;
271             if (p == null)
272             {
273                 return false;
274             }
275             return (_portName == p._portName) & (_trusted == p._trusted);
276         }
277
278         private void RaiseMessageReceivedEvent(EventHandler<MessageReceivedEventArgs> evt, MessageReceivedEventArgs args)
279         {
280             if (evt != null)
281             {
282                 evt(this, args);
283             }
284         }
285     }
286 }