/* * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using Tizen.Applications; namespace Tizen.Applications.Messages { /// /// The message port API provides functions to send and receive messages between applications. /// /// /// 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. /// If a remote application sends a message, the registered callback function of the local port is called. /// The trusted message-port API allows communications between applications that are signed by the same developer(author) certificate. /// public class MessagePort : IDisposable { private static readonly object s_lock = new object(); private static readonly HashSet s_portMap = new HashSet(); // The name of the local message port private readonly string _portName = null; // If true the message port is a trusted port, otherwise false it is not private readonly bool _trusted = false; // The local message port ID private int _portId = 0; // If true the message port is listening, otherwise false it is not private bool _listening = false; private Interop.MessagePort.message_port_message_cb _messageCallBack; /// /// Initializes the instance of the MessagePort class. /// /// The name of the local message port. /// If true, it is the trusted message port of application, otherwise false. /// Thrown when portName is null or empty. /// /// MessagePort messagePort = new MessagePort("SenderPort", true); /// public MessagePort(string portName, bool trusted) { if (String.IsNullOrEmpty(portName)) { MessagePortErrorFactory.ThrowException((int)MessagePortError.InvalidParameter, "Invalid PortName", "PortName"); } _portName = portName; _trusted = trusted; } /// /// Destructor of the MessagePort class. /// ~MessagePort() { Dispose(false); } /// /// Called when a message is received. /// /// /// MessagePort messagePort = new MessagePort("SenderPort", true); /// messagePort.MessageReceived += MessageReceivedCallback; /// static void MessageReceivedCallback(object sender, MessageReceivedEventArgs e) /// { /// Console.WriteLine("Message Received "); /// if (e.Remote.AppId != null) { /// Console.WriteLine("from :"+e.Remote.AppId); /// } /// } /// public event EventHandler MessageReceived; /// /// The name of the local message port. /// public string PortName { get { return _portName; } } /// /// If true, the message port is a trusted port, otherwise false. /// public bool Trusted { get { return _trusted; } } /// /// If true, the message port is listening, otherwise false. /// public bool Listening { get { return _listening; } } /// /// Register the local message port. /// /// Thrown when portName is already used, when there is an I/O error. /// Thrown when there is an invalid parameter. /// Thrown when out of memory. /// /// MessagePort messagePort = new MessagePort("SenderPort", true); /// messagePort.MessageReceived += MessageReceivedCallback; /// messagePort.Listen(); /// public void Listen() { lock (s_lock) { if (s_portMap.Contains(_portName)) { MessagePortErrorFactory.ThrowException((int)MessagePortError.InvalidOperation, _portName + "is already used"); } _messageCallBack = (int localPortId, string remoteAppId, string remotePortName, bool trusted, IntPtr message, IntPtr userData) => { MessageReceivedEventArgs args = new MessageReceivedEventArgs() { Message = new Bundle(new SafeBundleHandle(message, false)) }; if (!String.IsNullOrEmpty(remotePortName) && !String.IsNullOrEmpty(remoteAppId)) { args.Remote = new RemoteValues() { AppId = remoteAppId, PortName = remotePortName, Trusted = trusted }; } MessageReceived?.Invoke(this, args); }; _portId = _trusted ? Interop.MessagePort.RegisterTrustedPort(_portName, _messageCallBack, IntPtr.Zero) : Interop.MessagePort.RegisterPort(_portName, _messageCallBack, IntPtr.Zero); if (_portId <= 0) MessagePortErrorFactory.ThrowException(_portId, "RegisterPort", _portName); s_portMap.Add(_portName); _listening = true; } } /// /// Unregisters the local message port. /// /// Thrown when messageport is already stopped, when there is an I/O error, when the port is not found. /// Thrown when there is an invalid parameter. /// Thrown when out of memory. /// /// MessagePort messagePort = new MessagePort("SenderPort", true); /// messagePort.MessageReceived += MessageReceivedCallback; /// messagePort.Listen(); /// using (var message = new Tizen.Application.Bundle()) /// { /// message.AddItem("message", "a_string"); /// messagePort.Send(message, "ReceiverAppID", "ReceiverPort"); /// } /// messagePort.StopListening(); /// public void StopListening() { if (!_listening) { MessagePortErrorFactory.ThrowException((int)MessagePortError.InvalidOperation, "Already stopped"); } int ret = _trusted ? Interop.MessagePort.UnregisterTrustedPort(_portId) : Interop.MessagePort.UnregisterPort(_portId); if (ret != (int)MessagePortError.None) { MessagePortErrorFactory.ThrowException(ret, "Error Unregister port"); } lock (s_lock) { s_portMap.Remove(_portName); } _portId = 0; _listening = false; } /// /// Sends an untrusted message to the message port of a remote application. /// /// The message to be passed to the remote application, the recommended message size is under 4KB. /// The ID of the remote application. /// The name of the remote message port. /// Thrown when there is an I/O error, when the port is not found. /// Thrown when there is an invalid parameter. /// Thrown when out of memory. /// Thrown when message has exceeded the maximum limit(4KB). /// /// MessagePort messagePort = new MessagePort("SenderPort", true); /// messagePort.MessageReceived += MessageReceivedCallback; /// messagePort.Listen(); /// using (var message = new Tizen.Application.Bundle()) /// { /// message.AddItem("message", "a_string"); /// messagePort.Send(message, "ReceiverAppID", "ReceiverPort"); /// } /// public void Send(Bundle message, string remoteAppId, string remotePortName) { Send(message, remoteAppId, remotePortName, false); } /// /// Sends a message to the message port of a remote application. /// /// The message to be passed to the remote application, the recommended message size is under 4KB. /// The ID of the remote application. /// The name of the remote message port. /// If true, it is the trusted message port of remote application, otherwise false. /// Thrown when there is an I/O error, when the port is not found. /// Thrown when there is an invalid parameter. /// Thrown when out of memory. /// Thrown when message has exceeded the maximum limit(4KB). /// Thrown when the remote application is not signed with the same certificate. /// /// MessagePort messagePort = new MessagePort("SenderPort", true); /// messagePort.MessageReceived += MessageReceivedCallback; /// messagePort.Listen(); /// using (var message = new Tizen.Application.Bundle()) /// { /// message.AddItem("message", "a_string"); /// messagePort.Send(message, "ReceiverAppID", "ReceiverPort", true); /// } /// public void Send(Bundle message, string remoteAppId, string remotePortName, bool trusted) { if (!_listening) { MessagePortErrorFactory.ThrowException((int)MessagePortError.InvalidOperation, "Should start listen before send"); } if (message == null || message.SafeBundleHandle == null || message.SafeBundleHandle.IsInvalid) { MessagePortErrorFactory.ThrowException((int)MessagePortError.InvalidParameter, "message is null", "Message"); } int ret = trusted ? Interop.MessagePort.SendTrustedMessageWithLocalPort(remoteAppId, remotePortName, message.SafeBundleHandle, _portId) : Interop.MessagePort.SendMessageWithLocalPort(remoteAppId, remotePortName, message.SafeBundleHandle, _portId); if (ret != (int)MessagePortError.None) { if (ret == (int)MessagePortError.MaxExceeded) { MessagePortErrorFactory.ThrowException(ret, "Message has exceeded the maximum limit(4KB)", "Message"); } MessagePortErrorFactory.ThrowException(ret, "Can't send message"); } } /// /// Releases the unmanaged resources used by the MessagePort class specifying whether to perform a normal dispose operation. /// /// true for a normal dispose operation; false to finalize the handle. protected virtual void Dispose(bool disposing) { if (_listening) { try { StopListening(); } catch (Exception e) { Log.Warn(GetType().Namespace, "Exception in Dispose :" + e.Message); } } } /// /// Releases all resources used by the MessagePort class. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } }