internal static PayloadAsyncResult CreateFromHandle(IntPtr handle) { Interop.Cion.ErrorCode ret = Interop.CionPayloadAsyncResult.CionPayloadAsyncResultGetResult(handle, out int code); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Fail to get result code from the AsyncResult"); } ret = Interop.CionPayloadAsyncResult.CionPayloadAsyncResultGetPayloadID(handle, out string payloadId); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Fail to get payload id from the AsyncResult"); } ret = Interop.CionPayloadAsyncResult.CionPayloadAsyncResultGetPeerInfo(handle, out IntPtr peer); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Fail to get peerinfo from the AsyncResult"); } ret = Interop.CionPeerInfo.CionPeerInfoClone(peer, out PeerInfoSafeHandle clone); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to clone peer info."); } return(new PayloadAsyncResult((PayloadAsyncResultCode)code, new PeerInfo(clone), payloadId)); }
/// <summary> /// Saves file of payload to speicific path. /// </summary> /// <param name="path">The path of file to save.</param> /// <remarks> /// http://tizen.org/privilege/mediastorage is needed if the file path is relevant to media storage. /// http://tizen.org/privilege/externalstorage is needed if the file path is relevant to external storage. /// </remarks> /// <exception cref="ArgumentException">Thrown when the input file path is invalid.</exception> /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception> /// <since_tizen> 9 </since_tizen> public void SaveAsFile(string path) { Interop.Cion.ErrorCode ret = Interop.CionPayload.CionPayloadSaveAsFile(_handle, path); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to save as file."); } }
/// <summary> /// The constructor of SecurityInfo class. /// </summary> /// <exception cref="OutOfMemoryException">Thrown when there is not enough memory to continue the execution of the method.</exception> /// <since_tizen> 9 </since_tizen> public SecurityInfo() { Interop.Cion.ErrorCode ret = Interop.CionSecurity.CionSecurityCreate(out _handle); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to create security info."); } }
/// <summary> /// Subscribes the topic. /// </summary> /// <privilege>http://tizen.org/privilege/d2d.datasharing</privilege> /// <privilege>http://tizen.org/privilege/internet</privilege> /// <privlevel>public</privlevel> /// <exception cref="InvalidOperationException">Thrown when failed to subscribe.</exception> /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception> /// <since_tizen> 9 </since_tizen> public void Subscribe() { Interop.Cion.ErrorCode ret = Interop.CionGroup.CionGroupSubscribe(_handle); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to subscribe."); } }
/// <summary> /// Sets ondemand launch enabled flag. /// </summary> /// <param name="enable">Whether ondemand launch is enabled or not.</param> /// <privilege>http://tizen.org/privilege/d2d.remotelaunch</privilege> /// <privlevel>public</privlevel> /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception> /// <since_tizen> 9 </since_tizen> public void SetOndemandLaunchEnabled(bool enable) { Interop.Cion.ErrorCode ret = Interop.CionServer.CionServerSetOnDemandLaunchEnabled(_handle, enable); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to set ondemand launch enable"); } }
/// <summary> /// Disconnects with the peer. /// </summary> /// <param name="peerInfo">The peer to disconnect.</param> /// <exception cref="ArgumentException">Thrown when the given peer info is invalid.</exception> /// <since_tizen> 9 </since_tizen> public void Disconnect(PeerInfo peerInfo) { Interop.Cion.ErrorCode ret = Interop.CionServer.CionServerDisconnect(_handle, peerInfo?._handle); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to stop server."); } }
/// <summary> /// Publishes payload to current group. /// </summary> /// <param name="payload">The payload to publish.</param> /// <exception cref="ArgumentException">Thrown when the payload is invalid.</exception> /// <exception cref="InvalidOperationException">Thrown when failed to publish.</exception> /// <since_tizen> 9 </since_tizen> public void Publish(Payload payload) { Interop.Cion.ErrorCode ret = Interop.CionGroup.CionGroupPublish(_handle, payload?._handle); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to publish payload."); } }
/// <summary> /// Stops the listen operation. /// </summary> /// <exception cref="InvalidOperationException">Thrown when the server is not listening.</exception> /// <since_tizen> 9 </since_tizen> public void Stop() { Interop.Cion.ErrorCode ret = Interop.CionServer.CionServerStop(_handle); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to stop server."); } }
/// <summary> /// Connects with the cion server. /// </summary> /// <param name="peer">The peer to connect.</param> /// <privilege>http://tizen.org/privilege/d2d.datasharing</privilege> /// <privilege>http://tizen.org/privilege/internet</privilege> /// <privlevel>public</privlevel> /// <exception cref="InvalidOperationException">Thrown when the client cannot connect to server.</exception> /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception> /// <since_tizen> 9 </since_tizen> public void Connect(PeerInfo peer) { Interop.Cion.ErrorCode ret = Interop.CionClient.CionClientConnect(_handle, peer?._handle); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to connect."); } }
/// <summary> /// Stops discovering. /// </summary> /// <exception cref="InvalidOperationException">Thrown when the client is not discovering.</exception> /// <since_tizen> 9 </since_tizen> public void StopDiscovery() { Interop.Cion.ErrorCode ret = Interop.CionClient.CionClientStopDiscovery(_handle); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to stop discovery."); } }
/// <summary> /// Sends data synchronously to the connected cion server. /// </summary> /// <param name="data">The data to send.</param> /// <param name="timeout">The timeout of sending operation.</param> /// <exception cref="ArgumentException">Thrown when the given data is invalid.</exception> /// <exception cref="InvalidOperationException">Thrown when there is no connected cion server or failed to receive reply.</exception> /// <exception cref="TimeoutException">Thrown when a timeout occurred.</exception> /// <since_tizen> 9 </since_tizen> public byte[] SendData(byte[] data, int timeout) { Interop.Cion.ErrorCode ret = Interop.CionClient.CionClientSendData(_handle, data, data?.Length ?? -1, timeout, out IntPtr returnDataPtr, out int returnDataSize); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to send data."); } byte[] returnData = new byte[returnDataSize]; Marshal.Copy(returnDataPtr, returnData, 0, returnDataSize); Log.Info(LogTag, string.Format("Returned data size: {0}", returnDataSize)); return(returnData); }
/// <summary> /// Sends payload asynchronously to the connected cion server. /// </summary> /// <param name="payload">The payload to send.</param> /// <exception cref="ArgumentException">Thrown when the payload is not valid.</exception> /// <exception cref="InvalidOperationException">Thrown when there is no connected cion server or failed to send payload.</exception> /// <since_tizen> 9 </since_tizen> public Task <PayloadAsyncResult> SendPayloadAsync(Payload payload) { if (payload == null || payload.Id.Length == 0) { throw new ArgumentException("Payload is invalid."); } if (_tcsDictionary.ContainsKey(payload.Id)) { throw new InvalidOperationException("Payload is already sent."); } TaskCompletionSource <PayloadAsyncResult> tcs = new TaskCompletionSource <PayloadAsyncResult>(); _tcsDictionary[payload.Id] = tcs; Interop.CionClient.CionClientPayloadAsyncResultCb cb = new Interop.CionClient.CionClientPayloadAsyncResultCb( (IntPtr result, IntPtr userData) => { TaskCompletionSource <PayloadAsyncResult> tcsToReturn = _tcsDictionary[payload.Id]; PayloadAsyncResult resultPayload = null; try { resultPayload = PayloadAsyncResult.CreateFromHandle(result); } catch (Exception e) { Log.Error(LogTag, string.Format("Failed to create PayloadAsyncResult from result handle: {0}.", e.Message)); tcsToReturn.SetException(e); return; } tcsToReturn.SetResult(resultPayload); _payloadAsyncCbDictionary.Remove(resultPayload.PayloadId); _tcsDictionary.Remove(resultPayload.PayloadId); }); Interop.Cion.ErrorCode ret = Interop.CionClient.CionClientSendPayloadAsync(_handle, payload?._handle, cb, IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to send payload."); } _payloadAsyncCbDictionary[payload?.Id] = cb; return(tcs.Task); }
/// <summary> /// Sends the payload to a peer asynchronously. /// </summary> /// <param name="payload">The payload to send.</param> /// <param name="peerInfo">The peer to send payload.</param> /// <exception cref="ArgumentException">Thrown when the payload is not valid.</exception> /// <exception cref="InvalidOperationException">Thrown when there is no such connected cion client or failed to send payload.</exception> /// <since_tizen> 9 </since_tizen> public Task <PayloadAsyncResult> SendPayloadAsync(Payload payload, PeerInfo peerInfo) { if (payload == null || payload.Id.Length == 0 || peerInfo == null || peerInfo.UUID.Length == 0) { throw new ArgumentException("Payload or peerinfo is invalid."); } TaskCompletionSource <PayloadAsyncResult> tcs = new TaskCompletionSource <PayloadAsyncResult>(); _tcsDictionary[Tuple.Create(payload.Id, peerInfo.UUID)] = tcs; if (_payloadAsyncResultCb == null) { Interop.CionServer.CionServerPayloadAsyncResultCb cb = new Interop.CionServer.CionServerPayloadAsyncResultCb( (IntPtr result, IntPtr userData) => { PayloadAsyncResult resultPayload = null; try { resultPayload = PayloadAsyncResult.CreateFromHandle(result); } catch (Exception e) { Log.Error(LogTag, string.Format("Failed to create PayloadAsyncResult from result handle: {0}.", e.Message)); return; } TaskCompletionSource <PayloadAsyncResult> tcsToReturn = _tcsDictionary[Tuple.Create(resultPayload.PayloadId, resultPayload.PeerInfo.UUID)]; tcsToReturn.SetResult(resultPayload); _tcsDictionary.Remove(Tuple.Create(resultPayload.PayloadId, resultPayload.PeerInfo.UUID)); }); _payloadAsyncResultCb = cb; } Interop.Cion.ErrorCode ret = Interop.CionServer.CionServerSendPayloadAsync(_handle, peerInfo?._handle, payload?._handle, _payloadAsyncResultCb, IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to send payload."); } return(tcs.Task); }
/// <summary> /// Starts server and listens for requests from cion clients. /// </summary> /// <privilege>http://tizen.org/privilege/d2d.datasharing</privilege> /// <privilege>http://tizen.org/privilege/internet</privilege> /// <privlevel>public</privlevel> /// <exception cref="InvalidOperationException">Thrown when the listen operation is already in progress.</exception> /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception> /// <since_tizen> 9 </since_tizen> public void Listen() { if (_connectionRequestCb == null) { Interop.CionServer.CionServerConnectionRequestCb cb = new Interop.CionServer.CionServerConnectionRequestCb( (serviceName, peerInfo, userData) => { Interop.Cion.ErrorCode clone_ret = Interop.CionPeerInfo.CionPeerInfoClone(peerInfo, out PeerInfoSafeHandle clone); if (clone_ret != Interop.Cion.ErrorCode.None) { Log.Error(LogTag, "Failed to clone peer info"); return; } OnConnectionRequest(new PeerInfo(clone)); }); _connectionRequestCb = cb; } Interop.Cion.ErrorCode ret = Interop.CionServer.CionServerListen(_handle, _connectionRequestCb, IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to listen server."); } }
/// <summary> /// Starts discovering cion servers. /// </summary> /// <privilege>http://tizen.org/privilege/d2d.datasharing</privilege> /// <privilege>http://tizen.org/privilege/internet</privilege> /// <privlevel>public</privlevel> /// <exception cref="InvalidOperationException">Thrown when the discovery operation is already in progress.</exception> /// <exception cref="UnauthorizedAccessException">Thrown when an application does not have the privilege to access this method.</exception> /// <since_tizen> 9 </since_tizen> public void TryDiscovery() { if (_discoveredCb == null) { Interop.CionClient.CionClientServerDiscoveredCb cb = new Interop.CionClient.CionClientServerDiscoveredCb( (string serviceName, IntPtr peerInfo, IntPtr userData) => { Interop.Cion.ErrorCode clone_ret = Interop.CionPeerInfo.CionPeerInfoClone(peerInfo, out PeerInfoSafeHandle clone); if (clone_ret != Interop.Cion.ErrorCode.None) { Log.Error(LogTag, "Failed to clone peer info."); return; } OnDiscovered(new PeerInfo(clone)); }); _discoveredCb = cb; } Interop.Cion.ErrorCode ret = Interop.CionClient.CionClientTryDiscovery(_handle, _discoveredCb, IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to try discovery."); } }
/// <summary> /// The constructor of ClientBase class. /// </summary> /// <param name="serviceName">The name of service.</param> /// <param name="security">The security configuration.</param> /// <remarks>The maximum length of service name is 512.</remarks> /// <exception cref="ArgumentException">Thrown when the given service name is too long.</exception> /// <exception cref="InvalidOperationException">Thrown when there is not enough memory to continue the execution of the method.</exception> /// <since_tizen> 9 </since_tizen> public ClientBase(string serviceName, Cion.SecurityInfo security) { ServiceName = serviceName; SecuritySafeHandle handle = security?._handle; Interop.Cion.ErrorCode ret = Interop.CionClient.CionClientCreate(out _handle, serviceName, handle?.DangerousGetHandle() ?? IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to create client."); } _connectionResultCb = new Interop.CionClient.CionClientConnectionResultCb( (string service, IntPtr peerInfo, IntPtr result, IntPtr userData) => { Interop.Cion.ErrorCode clone_ret = Interop.CionPeerInfo.CionPeerInfoClone(peerInfo, out PeerInfoSafeHandle clone); if (clone_ret != Interop.Cion.ErrorCode.None) { Log.Error(LogTag, string.Format("Failed to clone peer info.")); return; } PeerInfo peer = new PeerInfo(clone); ConnectionResult connectionResult = new ConnectionResult(result); if (connectionResult.Status == ConnectionStatus.OK) { _peer = peer; } OnConnectionResult(peer, connectionResult); }); ret = Interop.CionClient.CionClientAddConnectionResultCb(_handle, _connectionResultCb, IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { _handle.Dispose(); throw CionErrorFactory.GetException(ret, "Failed to add connection status changed callback."); } _payloadRecievedCb = new Interop.CionClient.CionClientPayloadReceivedCb( (string service, IntPtr peerInfo, IntPtr payload, int status, IntPtr userData) => { Payload receivedPayload; Interop.CionPayload.CionPayloadGetType(payload, out Interop.CionPayload.PayloadType type); switch (type) { case Interop.CionPayload.PayloadType.Data: receivedPayload = new DataPayload(new PayloadSafeHandle(payload, false)); break; case Interop.CionPayload.PayloadType.File: receivedPayload = new FilePayload(new PayloadSafeHandle(payload, false)); break; default: Log.Error(LogTag, "Invalid payload type received."); return; } OnPayloadReceived(receivedPayload, (PayloadTransferStatus)status); }); ret = Interop.CionClient.CionClientAddPayloadReceivedCb(_handle, _payloadRecievedCb, IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { _handle.Dispose(); throw CionErrorFactory.GetException(ret, "Failed to add payload received callback."); } _disconnectedCb = new Interop.CionClient.CionClientDisconnectedCb( (string service, IntPtr peerInfo, IntPtr userData) => { Interop.Cion.ErrorCode clone_ret = Interop.CionPeerInfo.CionPeerInfoClone(peerInfo, out PeerInfoSafeHandle clone); if (clone_ret != Interop.Cion.ErrorCode.None) { Log.Error(LogTag, string.Format("Failed to clone peer info.")); return; } OnDisconnected(new PeerInfo(clone)); }); ret = Interop.CionClient.CionClientAddDisconnectedCb(_handle, _disconnectedCb, IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { _handle.Dispose(); throw CionErrorFactory.GetException(ret, "Failed to add disconnected callback."); } }
/// <summary> /// The constructor of ServerBase class. /// </summary> /// <param name="serviceName">The name of service.</param> /// <param name="displayName">The display name of service.</param> /// <param name="security">The security configuration.</param> /// <remarks>The maximum length of service name is 512.</remarks> /// <exception cref="ArgumentException">Thrown when the given service name is too long.</exception> /// <exception cref="InvalidOperationException">Thrown when there is not enough memory to continue the execution of the method.</exception> /// <since_tizen> 9 </since_tizen> public ServerBase(string serviceName, string displayName, Cion.SecurityInfo security) { ServiceName = serviceName; _displayName = displayName; Cion.SecuritySafeHandle handle = security?._handle; Interop.Cion.ErrorCode ret = Interop.CionServer.CionServerCreate(out _handle, serviceName, displayName, handle?.DangerousGetHandle() ?? IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to create server handle."); } _connectionResultCb = new Interop.CionServer.CionServerConnectionResultCb( (string service, IntPtr peerInfo, IntPtr result, IntPtr userData) => { Interop.Cion.ErrorCode clone_ret = Interop.CionPeerInfo.CionPeerInfoClone(peerInfo, out PeerInfoSafeHandle clone); if (clone_ret != Interop.Cion.ErrorCode.None) { Log.Error(LogTag, "Failed to clone peer info."); return; } OnConnectionResult(new PeerInfo(clone), new ConnectionResult(result)); }); ret = Interop.CionServer.CionServerAddConnectionResultCb(_handle, _connectionResultCb, IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { _handle.Dispose(); throw CionErrorFactory.GetException(ret, "Failed to add connection status changed callback."); } _dataReceivedCb = new Interop.CionServer.CionServerDataReceivedCb( (string service, IntPtr peerInfo, byte[] data, int dataSize, out IntPtr returnData, out int returnDataSize, IntPtr userData) => { Interop.Cion.ErrorCode clone_ret = Interop.CionPeerInfo.CionPeerInfoClone(peerInfo, out PeerInfoSafeHandle clone); if (clone_ret != Interop.Cion.ErrorCode.None) { Log.Error(LogTag, "Failed to clone peer info."); returnData = IntPtr.Zero; returnDataSize = -1; } byte[] returnDataRaw = OnDataReceived(data, new PeerInfo(clone)); returnDataSize = returnDataRaw.Length; returnData = Interop.Cion.Malloc(returnDataSize); Marshal.Copy(returnDataRaw, 0, returnData, returnDataSize); }); ret = Interop.CionServer.CionServerSetDataReceivedCb(_handle, _dataReceivedCb, IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { _handle.Dispose(); throw CionErrorFactory.GetException(ret, "Failed to set data received callback."); } _payloadRecievedCb = new Interop.CionServer.CionServerPayloadReceivedCb( (string service, IntPtr peerInfo, IntPtr payload, int status, IntPtr userData) => { Payload receivedPayload; Interop.CionPayload.CionPayloadGetType(payload, out Interop.CionPayload.PayloadType type); switch (type) { case Interop.CionPayload.PayloadType.Data: receivedPayload = new DataPayload(new PayloadSafeHandle(payload, false)); break; case Interop.CionPayload.PayloadType.File: receivedPayload = new FilePayload(new PayloadSafeHandle(payload, false)); break; default: Log.Error(LogTag, "Invalid payload type received."); return; } Interop.Cion.ErrorCode clone_ret = Interop.CionPeerInfo.CionPeerInfoClone(peerInfo, out PeerInfoSafeHandle clone); if (clone_ret != Interop.Cion.ErrorCode.None) { Log.Error(LogTag, "Failed to clone peer info."); return; } OnPayloadReceived(receivedPayload, new PeerInfo(clone), (PayloadTransferStatus)status); }); ret = Interop.CionServer.CionServerAddPayloadReceivedCb(_handle, _payloadRecievedCb, IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { _handle.Dispose(); throw CionErrorFactory.GetException(ret, "Failed to add payload received callback."); } _disconnectedCb = new Interop.CionServer.CionServerDisconnectedCb( (string service, IntPtr peerInfo, IntPtr userData) => { Interop.Cion.ErrorCode clone_ret = Interop.CionPeerInfo.CionPeerInfoClone(peerInfo, out PeerInfoSafeHandle clone); if (clone_ret != Interop.Cion.ErrorCode.None) { Log.Error(LogTag, string.Format("Failed to clone peer info.")); return; } OnDisconnected(new PeerInfo(clone)); }); ret = Interop.CionServer.CionServerAddDisconnectedCb(_handle, _disconnectedCb, IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { _handle.Dispose(); throw CionErrorFactory.GetException(ret, "Failed to add disconnected callback."); } }
/// <summary> /// The constructor of GroupBase class. /// </summary> /// <param name="topicName">The topic of group.</param> /// <param name="security">The security configuration.</param> /// <remarks>The maximum length of topic name is 512.</remarks> /// <exception cref="ArgumentException">Thrown when the given topic name is too long.</exception> /// <exception cref="InvalidOperationException">Thrown when there is not enough memory to continue the execution of the method.</exception> /// <since_tizen> 9 </since_tizen> public GroupBase(string topicName, Cion.SecurityInfo security) { Topic = topicName; Cion.SecuritySafeHandle handle = security?._handle; Interop.Cion.ErrorCode ret = Interop.CionGroup.CionGroupCreate(out _handle, topicName, handle?.DangerousGetHandle() ?? IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { throw CionErrorFactory.GetException(ret, "Failed to create group."); } _payloadReceivedCb = new Interop.CionGroup.CionGroupPayloadReceivedCb( (IntPtr group, IntPtr peerInfo, IntPtr payload, IntPtr userData) => { Payload receivedPayload; Interop.CionPayload.CionPayloadGetType(payload, out Interop.CionPayload.PayloadType type); switch (type) { case Interop.CionPayload.PayloadType.Data: receivedPayload = new DataPayload(new PayloadSafeHandle(payload, false)); break; case Interop.CionPayload.PayloadType.File: receivedPayload = new FilePayload(new PayloadSafeHandle(payload, false)); break; default: Log.Error(LogTag, "Invalid payload type received."); return; } Interop.Cion.ErrorCode clone_ret = Interop.CionPeerInfo.CionPeerInfoClone(peerInfo, out PeerInfoSafeHandle clone); if (clone_ret != Interop.Cion.ErrorCode.None) { Log.Error(LogTag, "Failed to clone peer info."); return; } OnPayloadReceived(receivedPayload, new PeerInfo(clone)); }); ret = Interop.CionGroup.CionGroupAddPayloadReceivedCb(_handle, _payloadReceivedCb, IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { _handle.Dispose(); throw CionErrorFactory.GetException(ret, "Failed to add payload received callback."); } _joinedCb = new Interop.CionGroup.CionGroupJoinedCb( (string name, IntPtr peerInfo, IntPtr userData) => { Interop.Cion.ErrorCode clone_ret = Interop.CionPeerInfo.CionPeerInfoClone(peerInfo, out PeerInfoSafeHandle clone); if (clone_ret != Interop.Cion.ErrorCode.None) { return; } OnJoined(new PeerInfo(clone)); }); ret = Interop.CionGroup.CionGroupAddJoinedCb(_handle, _joinedCb, IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { _handle.Dispose(); throw CionErrorFactory.GetException(ret, "Failed to add joined callback."); } _leftCb = new Interop.CionGroup.CionGroupLeftCb( (string name, IntPtr peerInfo, IntPtr userData) => { Interop.Cion.ErrorCode clone_ret = Interop.CionPeerInfo.CionPeerInfoClone(peerInfo, out PeerInfoSafeHandle clone); if (clone_ret != Interop.Cion.ErrorCode.None) { return; } OnLeft(new PeerInfo(clone)); }); ret = Interop.CionGroup.CionGroupAddLeftCb(_handle, _leftCb, IntPtr.Zero); if (ret != Interop.Cion.ErrorCode.None) { _handle.Dispose(); throw CionErrorFactory.GetException(ret, "Failed to add joined callback."); } }