jueves, 17 de diciembre de 2009

Desconectar a un usuario de RRAS (usando MPRAPI y C#)

Lo más tedioso es definir las estructuras y los métodos externos;
Una vez hecho, solo hay que articular las llamadas.
No me he entretenido en el control de errores ni en hacer Dispose de las estructuras, para lo que habría que usar ¿Marshal.FreeHGlobal?;
Son aconsejables estos dos puntos si se quiere usar en producción.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Mprapi
{
public enum ROUTER_INTERFACE_TYPE : uint
{

ROUTER_IF_TYPE_CLIENT,

ROUTER_IF_TYPE_HOME_ROUTER,

ROUTER_IF_TYPE_FULL_ROUTER,

ROUTER_IF_TYPE_DEDICATED,

ROUTER_IF_TYPE_INTERNAL,

ROUTER_IF_TYPE_LOOPBACK,

ROUTER_IF_TYPE_DIALOUT

}

public enum ROUTER_CONNECTION_STATE : uint
{

ROUTER_IF_STATE_UNREACHABLE,

ROUTER_IF_STATE_DISCONNECTED,

ROUTER_IF_STATE_CONNECTING,

ROUTER_IF_STATE_CONNECTED

}
public enum RAS_PORT_CONDITION :uint
{
RAS_PORT_NON_OPERATIONAL,
RAS_PORT_DISCONNECTED,
RAS_PORT_CALLING_BACK,
RAS_PORT_LISTENING,
RAS_PORT_AUTHENTICATING,
RAS_PORT_AUTHENTICATED,
RAS_PORT_INITIALIZING
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct RAS_CONNECTION_0
{
public IntPtr hConnection;
public IntPtr hInterface;
public uint dwConnectDuration;
public ROUTER_INTERFACE_TYPE dwInterfaceType;
public uint dwConnectionFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)257)]
public string wszInterfaceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)257)]
public string wszUserName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)16)]
public string wszLogonDomain;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)17)]
public string wszRemoteComputer;

};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal struct RAS_PORT_0
{
public IntPtr hPort;
public IntPtr hConnection;
public RAS_PORT_CONDITION dwPortCondition;
public uint dwTotalNumberOfCalls;
public uint dwConnectDuration;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)17)]
public string wszPortname;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)17)]
public string wszMedianame;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)129)]
public string wszDevicename;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = (int)17)]
public string wszDeviceType;

};



class Program
{
[DllImport("mprapi.dll", CharSet = CharSet.Unicode)]
static extern int MprAdminServerConnect(string lpwsServerName, ref IntPtr phMprServer);
//
[DllImport("Mprapi.dll")]
public static extern uint MprAdminConnectionEnum(IntPtr hRasServer,
uint dwLevel, ref IntPtr connectionsStartPoint , int dwPrefMaxLen,
ref IntPtr lpdwEntriesRead, ref IntPtr lpdwTotalEntries,
ref ulong lpdwResumeHandle

);
[DllImport("Mprapi.dll")]
public static extern uint MprAdminPortEnum(IntPtr hRasServer,
uint dwLevel, IntPtr hconnection, ref IntPtr buf,
int dwPrefMaxLen,
ref IntPtr lpdwEntriesRead, ref IntPtr lpdwTotalEntries,
ref ulong lpdwResumeHandle

);
[DllImport("Mprapi.dll")]
public static extern uint MprAdminPortDisconnect(IntPtr hRasServer,
IntPtr hport);
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("Hay que pasar el usuario a desconectar.");
return;
}
try
{
string usuario_desconectar = args[0];
IntPtr phMprServer = IntPtr.Zero;
MprAdminServerConnect(null, ref phMprServer);
//Console.WriteLine(phMprServer.ToString());

IntPtr connectionsStartPoint = new IntPtr();
List connections = new List();


IntPtr EntriesRead = IntPtr.Zero;
IntPtr TotalEntries = IntPtr.Zero;
ulong ResumeHandle = 0;
uint retConEnum = MprAdminConnectionEnum(phMprServer, 0,
ref connectionsStartPoint, -1, ref EntriesRead, ref TotalEntries, ref ResumeHandle);

//Console.WriteLine(TotalEntries.ToInt32().ToString());
for (int i = 0; i < EntriesRead.ToInt32(); i++)
{
connections.Add((RAS_CONNECTION_0)Marshal.PtrToStructure(connectionsStartPoint, typeof(RAS_CONNECTION_0)));
connectionsStartPoint = new IntPtr(connectionsStartPoint.ToInt32() + Marshal.SizeOf(connections.First()));
//Console.WriteLine(connections[i].wszUserName);
}
foreach (var it in connections)
{
if (it.wszUserName == usuario_desconectar)
{
desconectar(it.hConnection, phMprServer);
//Console.WriteLine(it.hConnection);
}
}
}
catch (Exception e)
{
Console.WriteLine("Se produjo el error: " + e.Message);
}
}

private static void desconectar(IntPtr hcon, IntPtr hserver)
{
RAS_PORT_0 est = new RAS_PORT_0();
IntPtr buf = new IntPtr();
IntPtr EntriesRead = IntPtr.Zero;
IntPtr TotalEntries = IntPtr.Zero;
ulong ResumeHandle = 0;
uint retConEnum = MprAdminPortEnum(hserver,0,hcon,
ref buf, -1, ref EntriesRead, ref TotalEntries, ref ResumeHandle);
est = (RAS_PORT_0)Marshal.PtrToStructure(buf, typeof(RAS_PORT_0));
Console.WriteLine(est.wszDevicename + " -> " + est.hPort.ToString());
uint r = MprAdminPortDisconnect(hserver, est.hPort);
Console.WriteLine("Cerrar " + est.hPort.ToString() + ":" + r.ToString());
}
}
}