/*
Copyright 2009-2014 Intel Corporation
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.
*/
/*
This file along with WebRTC.dll contains all the classes and code needed
to use WebRTC from C#. All you need to do is include this WebRTC.cs file
in your project, add "using OpenSource.WebRTC" to your code and start
using WebRTC. Documentation at: http://opentools.homeip.net/webrtc
*/
using System;
using System.IO;
using System.Net;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
namespace OpenSource.WebRTC
{
public class WebRTCCommons
{
#region String Helpers
private static string ReadString(IntPtr source, int length)
{
return (Marshal.PtrToStringAnsi(source, length));
}
private static string ReadString(IntPtr source)
{
return (Marshal.PtrToStringAnsi(source));
}
#endregion
#region IPAddress Helpers
#region P-Invoke Declarations
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr ILibWrapper_SockAddr_GetAddressString(IntPtr addr, IntPtr buffer, int bufferLength);
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern ushort ILibWrapper_SockAddr_GetPort(IntPtr addr);
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr ILibWrapper_SockAddr_FromString(IntPtr buffer, ushort port);
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr ILibWrapper_SockAddr_FromString6(IntPtr addr, ushort port);
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern void ILibWrapper_FreeSockAddr(IntPtr addr);
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr ILibWrapper_SockAddr_FromBytes(IntPtr buffer, int offset, int length);
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern int ILibWrapper_SockAddrIn6_Size();
#endregion
public static int GetSockAddrIn6Size()
{
return (ILibWrapper_SockAddrIn6_Size());
}
///
/// Returns the port number specified by the native sockaddr structure, in host order.
/// Note: Supports both IPv6 and IPv4
///
/// The native sockaddr structure
/// Port number in host order
public static ushort GetPort(IntPtr sockaddr)
{
return (ILibWrapper_SockAddr_GetPort(sockaddr));
}
///
/// Converts a native sockaddr structure to a managed IPEndPoint object.
/// Note: Supports both IPv6 and IPv4
///
/// The native sockaddr structure
/// An IPEndPoint object representing the sockaddr structure
public static IPEndPoint GetIPEndPoint(IntPtr sockaddr)
{
return (new IPEndPoint(GetIPAddress(sockaddr), (int)GetPort(sockaddr)));
}
public static IPEndPoint GetIPEndPoint(byte[] buffer)
{
return (GetIPEndPoint(buffer, 0, buffer.Length));
}
public static IPEndPoint GetIPEndPoint(byte[] buffer, int offset, int length)
{
IntPtr native = Marshal.AllocHGlobal(length);
Marshal.Copy(buffer, offset, native, length);
IntPtr sockaddr = ILibWrapper_SockAddr_FromBytes(native, 0, length);
IPEndPoint retVal = GetIPEndPoint(sockaddr);
ILibWrapper_FreeSockAddr(sockaddr);
return (retVal);
}
///
/// Returns the IP Address specified by the native sockaddr structure.
/// Note: Supports both IPv6 and IPv4
///
/// The native sockaddr structure
/// An IPAddress object representing the address specified by sockaddr
public static IPAddress GetIPAddress(IntPtr sockaddr)
{
if (sockaddr != IntPtr.Zero)
{
IntPtr buffer = Marshal.AllocHGlobal(255);
IntPtr str = ILibWrapper_SockAddr_GetAddressString(sockaddr, buffer, 255);
IPAddress retVal = IPAddress.Parse(ReadString(str));
Marshal.FreeHGlobal(buffer);
return (retVal);
}
else
{
return (null);
}
}
///
/// Converts a managed IPEndPoint object to a native sockaddr structure. You MUST call "FreeSockAddr" to release memory consumed by the native structure.
/// Note: Supports both IPv6 and IPv4
///
/// The IPEndPoint to convert
/// Managed pointer to sockaddr* representing the IPEndPoint
public static IntPtr GetSockAddr(IPEndPoint endPoint)
{
return (GetSockAddr(endPoint.Address, (ushort)endPoint.Port));
}
///
/// Creates a native sockaddr structure, representing the IPAddress and port specified. You MUST call "FreeSockAddr" to release the memory used by the native structure
/// Note: Supports both IPv6 and IPv4
///
/// IPAddress to specify in the structure
/// The port number (in host order) to specify
/// Managed pointer to sockaddr* representing the IPEndPoint
public static IntPtr GetSockAddr(IPAddress addr, ushort port)
{
IntPtr buffer = Marshal.StringToHGlobalAnsi(addr.ToString());
IntPtr RetVal;
switch (addr.AddressFamily)
{
case System.Net.Sockets.AddressFamily.InterNetwork:
RetVal = ILibWrapper_SockAddr_FromString(buffer, port);
break;
case System.Net.Sockets.AddressFamily.InterNetworkV6:
RetVal = ILibWrapper_SockAddr_FromString6(buffer, port);
break;
default:
RetVal = IntPtr.Zero;
break;
}
Marshal.FreeHGlobal(buffer);
return (RetVal);
}
///
/// Releases memory that was allocated to store the native sockaddr structure created by "GetSockAddr".
///
/// The structure to free
public static void FreeSockAddr(IntPtr SockAddr)
{
if (SockAddr != IntPtr.Zero)
{
ILibWrapper_FreeSockAddr(SockAddr);
}
}
#endregion
#region Custom Awaiter Class
///
/// An awaitable Template, so that you can take advantage of await and continueWith, without relying on Tasks
///
/// The result type for GetResult and await
public class CustomAwaiter
{
private TaskCompletionSource mTCS;
private ConfiguredTaskAwaitable.ConfiguredTaskAwaiter mConfigedTaskAwaiter;
private Action, int> mSetStateFlags;
private bool _captureContext;
///
/// Instantiates a new reusable Awaiter
///
public CustomAwaiter(bool captureContext = false)
{
_captureContext = captureContext;
mTCS = new TaskCompletionSource();
mConfigedTaskAwaiter = mTCS.Task.ConfigureAwait(captureContext).GetAwaiter();
FieldInfo stateFlagsField = typeof(Task).GetField("m_stateFlags", BindingFlags.Instance | BindingFlags.NonPublic);
ParameterExpression taskExp = Expression.Parameter(typeof(Task));
ParameterExpression intExp = Expression.Parameter(typeof(int));
MemberExpression M = Expression.Field(taskExp, stateFlagsField);
BinaryExpression AssignExp = Expression.Assign(M, intExp);
mSetStateFlags = Expression.Lambda, int>>(AssignExp, taskExp, intExp).Compile();
}
///
/// Get's the underlying awaiter object. (Note: Used by compiler)
///
/// Awaiter
public ConfiguredTaskAwaitable.ConfiguredTaskAwaiter GetAwaiter()
{
return (mConfigedTaskAwaiter);
}
///
/// Marks the completion of an asyncronous operation.
///
/// Completion object to pass to the awaiter
public void SetComplete(T val)
{
mTCS.TrySetResult(val);
}
///
/// Returns the underlying Task object
///
public Task Task
{
get
{
return (mTCS.Task);
}
}
///
/// Reset the state of the Awaiter, so it can be re-used
///
public void Reset()
{
mTCS = new TaskCompletionSource(_captureContext);
mConfigedTaskAwaiter = mTCS.Task.ConfigureAwait(false).GetAwaiter();
}
}
#endregion
///
/// Managed wrapper for a Microstack Chain
///
public class MicrostackChain : IDisposable
{
#region RemoteLogging Details
public enum RemoteLogging_Modules
{
UNKNOWN = 0x00, //!< UNKNOWN Module
WebRTC_STUN_ICE = 0x02, //!< WebRTC: STUN/ICE
WebRTC_DTLS = 0x04, //!< WebRTC: DTLS
WebRTC_SCTP = 0x08, //!< WebRTC: SCTP
Agent_GuardPost = 0x10, //!< Mesh Agent: Guard Post
Agent_P2P = 0x20, //!< Mesh Agent: Peer to Peer
Agent_KVM = 0x200, //!< Mesh AGent: KVM
Microstack_AsyncSocket = 0x40, //!< Microstack: AsyncSocket, AsyncServerSocket, AsyncUDPSocket
Microstack_Web = 0x80, //!< Microstack: WebServer, WebSocket, WebClient
Microstack_Pipe = 0x400,//!< Microstack: Pipe
Microstack_Generic = 0x100 //!< Microstack: Generic
}
public enum RemoteLogging_Flags
{
NONE = 0x00, //!< NONE
DisableLogging = 0x01, //!< DISABLED
VerbosityLevel_1 = 0x02, //!< Verbosity Level 1
VerbosityLevel_2 = 0x04, //!< Verbosity Level 2
VerbosityLevel_3 = 0x08, //!< Verbosity Level 3
VerbosityLevel_4 = 0x10, //!< Verbosity Level 4
VerbosityLevel_5 = 0x20 //!< Verbosity Level 5
}
public void RemoteLog(RemoteLogging_Modules module, RemoteLogging_Flags flag, string msg)
{
IntPtr astr = Marshal.StringToHGlobalAnsi(msg);
ILibWrapper_RemoteLogging_Print(mChain, module, flag, astr);
Marshal.FreeHGlobal(astr);
}
#endregion
public ushort LoggingPort
{
get
{
return (_loggingPort);
}
set
{
_loggingPort = ILibWrapper_StartDefaultLogger(mChain, value);
}
}
private ushort _loggingPort = 0;
public readonly IntPtr mBaseTimer;
public readonly IntPtr mChain;
private Thread mChainThread = null;
private bool disposing = false;
public delegate void StopChainHandler(MicrostackChain sender);
public event StopChainHandler OnStopChain;
#region Chain Management
#region P-Invoke Declarations
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void ILibLifeTime_OnCallback(IntPtr obj);
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr ILibWrapper_CreateMicrostackChain();
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern void ILibWrapper_StartChain(IntPtr chain);
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern void ILibWrapper_StopChain(IntPtr chain);
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern int ILibWrapper_IsChainRunning(IntPtr chain);
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr ILibWrapper_DLL_GetBaseTimer(IntPtr chain);
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern void ILibWrapper_LifeTimeAddEx(IntPtr LifetimeMonitorObject, IntPtr data, int ms, ILibLifeTime_OnCallback Callback, ILibLifeTime_OnCallback Destroy);
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern void ILibWrapper_LifeTimeRemove(IntPtr LifeTimeToken, IntPtr data);
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern int ILibWrapper_DLL_IsChainDisposing(IntPtr chain);
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern ushort ILibWrapper_StartDefaultLogger(IntPtr chain, ushort portNumber);
[DllImport("WebRTC.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
private static extern void ILibWrapper_RemoteLogging_Print(IntPtr chain, RemoteLogging_Modules module, RemoteLogging_Flags flags, IntPtr msg);
#endregion
#region LifeTimeMonitor
public delegate void LifeTimeExpirationHandler(MicrostackChain sender, object data);
private Dictionary