Click here to Skip to main content
Licence 
First Posted 29 Jun 2003
Views 160,735
Bookmarked 77 times

A web based dialup Internet application

By | 6 Jul 2003 | Article
A web application to connect and disconnect from a dial up Internet session

Sample Image - webdialup.gif

Introduction

I recently changed my home network, basically I added a server to connect the network to the Internet. Unfortunately where I live we can't get broadband Internet, so the Internet connection server needs to dial into our ISP. I needed a simple way to connect, disconnect and see how long the connection has been up. Normally I would use terminal services to establish and view the connection, but since my wife also uses the Internet I needed another simpler way, one that even my wife can use. I built this web application, that displays the current connection's statistics or shows the phonebook entries so that the user can connect.

Using the code

I've wrapped up some of the RAS API's so I could use them with P/Invoke. They are:

  • RasEnumConnections
  • RasGetConnectionStatistics
  • RasHangUp
  • RasEnumEntries
  • InternetDial

I also had to create some structures that these API's could use:

  • RASCONN
  • RasEntryName
  • RasStats

I created a simple class called RASDisplay which has the following methods and properties:

Methods

  • int Connect(string Connection)
  • void Disconnect()

Properties

  • bool IsConnected
  • string ConnectionName
  • double BytesReceived
  • double BytesTransmitted
  • string[] Connections
  • string Duration

The RASDisplay class takes care of all the complexity of using the RAS API. If you not familiar with using the RAS API, you have to pass in the structure sizes, so the API knows which version you are working with. The constructor for this class uses the following code to set the above properties:

private string m_duration;
private string m_ConnectionName;
private string[] m_ConnectionNames;
private double m_TX;
private double m_RX;
private bool m_connected;
private IntPtr m_ConnectedRasHandle;

public RASDisplay()
{
    m_connected = true;

    RAS lpras = new RAS();
    RASCONN lprasConn = new RASCONN();            

    lprasConn.dwSize = Marshal.SizeOf(typeof(RASCONN));
    lprasConn.hrasconn = IntPtr.Zero;

    int lpcb = 0;
    int lpcConnections = 0;
    int nRet = 0;
    lpcb = Marshal.SizeOf(typeof(RASCONN));


    nRet = RAS.RasEnumConnections(ref lprasConn, ref lpcb, 
                                         ref lpcConnections);


    if(nRet != 0)
    {
        m_connected = false;
        return;
    }

    if(lpcConnections > 0)
    {
        RasStats stats = new RasStats();

        m_ConnectedRasHandle = lprasConn.hrasconn;
        RAS.RasGetConnectionStatistics(lprasConn.hrasconn, stats);

        m_ConnectionName = lprasConn.szEntryName;

        //Work out our duration 
        int Hours = 0;
        int Minutes = 0;
        int Seconds = 0;

        //The RasStats duration is in milliseconds
        Hours = ((stats.dwConnectDuration /1000) /3600);
        Minutes = ((stats.dwConnectDuration /1000) /60) - 
                                              (Hours * 60);
        Seconds = ((stats.dwConnectDuration /1000)) - 
                           (Minutes * 60) - (Hours * 3600);

        m_duration = Hours  +  " hours "  + Minutes + 
                " minutes " + Seconds + " secs";

        //set the bytes transferred and received
        m_TX = stats.dwBytesXmited;
        m_RX = stats.dwBytesRcved;

    }
    else
    {
        //we aren't connected
        m_connected = false;
    }

    //Find the names of the connections we could dial
    int lpNames = 1;
    int entryNameSize=Marshal.SizeOf(typeof(RasEntryName));
    int lpSize=lpNames*entryNameSize;
    RasEntryName[] names=new RasEntryName[lpNames];
    for(int i=0;i<names.Length;i++)
    {
        names[i].dwSize=entryNameSize;
    }

    uint retval = RAS.RasEnumEntries(null,null,names,
                                 ref lpSize,out lpNames);

    m_ConnectionNames = new string[lpNames];

    if(lpNames>0)
    {                
        for(int i=0;i<lpNames;i++)
        {
            m_ConnectionNames[i] = names[i].szEntryName;
        }
    }
}

The code to connect to the Internet uses the InternetDial WinInet API:

public int Connect(string sConnection)
{
    int intConnection = 0;
    uint INTERNET_AUTO_DIAL_UNATTENDED = 2;
    int retVal = RAS.InternetDial(IntPtr.Zero, sConnection,
            INTERNET_AUTO_DIAL_UNATTENDED,ref intConnection,0);
    return retVal;
}

The code to disconnect is very simple as well:

public void Disconnect()
{
    RAS.RasHangUp(m_ConnectedRasHandle);
}

The web application that uses the RASDisplay class looks like:

protected System.Web.UI.WebControls.Label lblName;
protected System.Web.UI.WebControls.Label lblDuration;
protected System.Web.UI.WebControls.Label lblTransmitted;
protected System.Web.UI.WebControls.DataGrid dgAllConnections;
protected System.Web.UI.HtmlControls.HtmlTable tblCurrentConnection;
protected System.Web.UI.WebControls.Button btnDisconnect;
protected System.Web.UI.WebControls.Label lblRecieved;

private void Page_Load(object sender, System.EventArgs e)
{
    if(!IsPostBack)
    {
        BindData();
    }
}

private void BindData()
{
    try
    {
        RASDisplay display = new RASDisplay();

        lblName.Text = display.ConnectionName;
        lblDuration.Text = display.Duration;
        lblRecieved.Text = display.BytesReceived.ToString();
        lblTransmitted.Text = display.BytesTransmitted.ToString();

        if(!display.IsConnected)
        {
            //show the table with stats
            tblCurrentConnection.Visible = false;
        }
        else
        {
            //show the tables with available connections
            dgAllConnections.Visible = false;
        }

        //bind the data
        dgAllConnections.DataSource = display.Connections;
        dgAllConnections.DataBind();

    }
    catch(Exception e){
        Response.Write(e.Message);
    }
}

protected void btnConnect_Click(object sender, EventArgs e)
{
    RASDisplay rasDisplay = new RASDisplay();

    //need to find the text in the first column of the datagrid
    Button btnSender = (Button) sender;
    DataGridItem ob =  (DataGridItem) btnSender.Parent.Parent;

    int ErrorVal = rasDisplay.Connect(ob.Cells[1].Text);

    if(ErrorVal != 0)
    {
        Response.Write(ErrorVal);
    }
    else
    {
        //redirect to the same page, so the display 
        //is refreshed with stats
        Response.Redirect("Default.aspx");
    }
}

protected void btnDisConnect_Click(object sender, EventArgs e)
{
    RASDisplay rasDisplay = new RASDisplay();
    rasDisplay.Disconnect();
    //redirect to the same page, so the display is 
    //refreshed with available connections
    Response.Redirect("Default.aspx");
}

The web application has a DataGrid that displays all the connections on the machine, this DataGrid only gets displayed if the computer isn't connected to the Internet. Otherwise a table with the connection's statistics gets displayed. The web page has a meta refresh tag, to keep the statistics up to date.

Know issues

Currently the Connect method calls InternetDial, this method takes the name of the connection. If this connection doesn't have a password saved, the call will fail. In a future version I'd like to change the way the application connects to the Internet, maybe using RASDial and have the application store the username and password for the user (or require them to enter it ? )

History

  • Article Created: 30/06/2003
  • Updated 7/7/2003 - Just a bug fix, if the user had more than one dialup internet phonebook, they might have some problems.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Dan_P

Web Developer

Australia Australia

Member

I've been programming for a few years now. I blog regularly at httpcode.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionAlready have Internet connection but how to use RAS with that please help PinmemberUmesh Deshmukh351:09 22 Mar '12  
GeneralYou Deserve a 5. Good stuff PinmemberAriel Delgado21:14 4 Nov '10  
GeneralVery Informative PinmemberMohammad Rastkar3:52 24 Jun '08  
GeneralDial up connnection in c#/.net Pinmembersatheesh.yuva21:13 13 Apr '08  
QuestionGreat Job - Need help translating it to VB.NET PinmemberMember 443888611:11 3 Apr '08  
When I translate the code it does not work when the call is made to RasEnumEntries Function:
Here is the code:

Imports System.Runtime.InteropServices
Namespace Utilities.Dialup.RAS
 
Public Enum RasFieldSizeConstants
RAS_MaxDeviceType = 16
RAS_MaxPhoneNumber = 128
RAS_MaxIpAddress = 15
RAS_MaxIpxAddress = 21
#If WINVER4 Then
RAS_MaxEntryName =256
RAS_MaxDeviceName =128
RAS_MaxCallbackNumber =RAS_MaxPhoneNumber
#Else
RAS_MaxEntryName = 20
RAS_MaxDeviceName = 32
RAS_MaxCallbackNumber = 48
#End If
 
RAS_MaxAreaCode = 10
RAS_MaxPadType = 32
RAS_MaxX25Address = 200
RAS_MaxFacilities = 200
RAS_MaxUserData = 200
RAS_MaxReplyMessage = 1024
RAS_MaxDnsSuffix = 256
UNLEN = 256
PWLEN = 256
DNLEN = 15
End Enum
 
_
Public Structure GUID
Public Data1 As UInteger
Public Data2 As UShort
Public Data3 As UShort
_
Public Data4() As Byte
 
End Structure
 
_
Public Structure RASCONN
Public dwSize As Integer
Public hrasconn As IntPtr
_
Public szEntryName As String
_
Public szDeviceType As String
_
Public szDeviceName As String
'MAX_PAPTH=260
_
Public szPhonebook As String
Public dwSubEntry As Integer
Public guidEntry As GUID
#If (WINVER501) Then
Public dwFlags AS integer
Public luid AS LUID
#End If
End Structure
 
_
Public Structure LUID
Dim LowPart As Integer
Dim HighPart As Integer
End Structure
 
_
Public Structure RasEntryName
Public dwSize As Integer
_
Public szEntryName As String
#If WINVER5 Then
public dwFlags as Integer
_
Public szPhonebookPath as String
#End If
End Structure
 
_
Public Class RasStats
Public dwSize As Integer = Marshal.SizeOf(GetType(RasStats))
Public dwBytesXmited As Integer
Public dwBytesRcved As Integer
Public dwFramesXmited As Integer
Public dwFramesRcved As Integer
Public dwCrcErr As Integer
Public dwTimeoutErr As Integer
Public dwAlignmentErr As Integer
Public dwHardwareOverrunErr As Integer
Public dwFramingErr As Integer
Public dwBufferOverrunErr As Integer
Public dwCompressionRatioIn As Integer
Public dwCompressionRatioOut As Integer
Public dwBps As Integer
Public dwConnectDuration As Integer
End Class
 
Public Class RAS
 
Sub New()
 
End Sub
 
_
Public Shared Function RasEnumConnections( _
ByRef lprasconn As RASCONN _
, ByRef lpcb As Integer _
, ByRef lpcConnections As Integer _
) As Integer
 
End Function
 

 
'''
'''
'''

''' handle to the connection
''' buffer to receive statistics
'''
'''
_
Public Shared Function RasGetConnectionStatistics( _
ByVal hRasConn As IntPtr _
, ByRef lpStatistics As RasStats _
) As UInteger
 
End Function
 
'''
'''
'''

''' handle to the RAS connection to hang up
'''
'''
_
Public Shared Function RasHangUp( _
ByVal hrasconn As IntPtr _
) As UInteger
 
End Function
 
'''
'''
'''

''' reserved, must be NULL
''' pointer to full path and file name of phone-book file
''' buffer to receive phone-book entries
''' size in bytes of buffer
''' number of entries written to buffer
'''
'''
_
Public Shared Function RasEnumEntries( _
ByVal reserved As String, _
ByVal lpszPhonebook As String, _
ByRef lprasentryname As RasEntryName(), _
ByRef lpcb As Integer, _
ByRef lpcEntries As Integer _
) As UInteger
End Function

 

_
Public Shared Function InternetDial( _
ByVal hwnd As IntPtr, _
ByVal lpszConnectoid As String, _
ByVal dwFlags As UInteger, _
ByRef lpdwConnection As Integer, _
ByVal dwReserved As UInteger _
) As Integer
End Function
 
End Class
 
Public Class RASDisplay
Private m_duration As String
Private m_ConnectionName As String
Private m_ConnectionNames() As String
Private m_TX As Double
Private m_RX As Double
Private m_connected As Boolean
Private m_ConnectedRasHandle As IntPtr
 
Sub New()
m_connected = True
 
Dim lpras As RAS = New RAS
Dim lprasConn As RASCONN = New RASCONN
 
lprasConn.dwSize = Marshal.SizeOf(GetType(RASCONN))
lprasConn.hrasconn = IntPtr.Zero
 
Dim lpcb As Integer = 0
Dim lpcConnections As Integer = 0
Dim nRet As Integer = 0
lpcb = Marshal.SizeOf(GetType(RASCONN))
 
nRet = RAS.RasEnumConnections(lprasConn, lpcb, lpcConnections)
 
If nRet <> 0 Then
m_connected = False
Return
End If
 
If lpcConnections > 0 Then
 
Dim stats As RasStats = New RasStats
m_ConnectedRasHandle = lprasConn.hrasconn
RAS.RasGetConnectionStatistics(lprasConn.hrasconn, stats)
 
m_ConnectionName = lprasConn.szEntryName
 
Dim Hours As Integer = 0
Dim Minutes As Integer = 0
Dim Seconds As Integer = 0
 
Hours = ((stats.dwConnectDuration / 1000) / 3600)
Minutes = ((stats.dwConnectDuration / 1000) / 60) - (Hours * 60)
Seconds = ((stats.dwConnectDuration / 1000)) - (Minutes * 60) - (Hours * 3600)
 
m_duration = Hours + " hours " + Minutes + " minutes " + Seconds + " secs"
m_TX = stats.dwBytesXmited
m_RX = stats.dwBytesRcved
 
Else
m_connected = False
End If
 
Dim lpNames As Integer = 1
Dim entryNameSize As Integer = 0
Dim lpSize As Integer = 0
Dim names() As RasEntryName
 
entryNameSize = Marshal.SizeOf(GetType(RasEntryName))
lpSize = lpNames * entryNameSize
 
ReDim names(lpNames - 1)
names(0).dwSize = entryNameSize
 
Dim retval As UInteger = RAS.RasEnumEntries(Nothing, Nothing, names, lpSize, lpNames)

' if we have more than one connection, we need to do it again
If lpNames > 1 Then
ReDim names(lpNames)
For i As Integer = 0 To names.Length - 1
names(0).dwSize = entryNameSize
Next
retval = RAS.RasEnumEntries(Nothing, Nothing, names, lpSize, lpNames)
 
End If
ReDim m_ConnectionNames(names.Length)
 
If lpNames > 0 Then
For i As Integer = 0 To names.Length - 1
m_ConnectionNames(i) = names(i).szEntryName
Next
End If
End Sub
 

Public ReadOnly Property Duration() As String
Get
Return IIf(m_connected, m_duration, "")
End Get
End Property
 
Public ReadOnly Property Connections() As String()
Get
Return m_ConnectionNames
End Get
End Property
 
Public ReadOnly Property BytesTransmitted() As Double
Get
Return IIf(m_connected, m_TX, 0)
End Get
End Property
 
Public ReadOnly Property BytesReceived() As Double
Get
Return IIf(m_connected, m_RX, 0)
End Get
End Property
 
Public ReadOnly Property ConnectionName() As String
Get
Return IIf(m_connected, m_ConnectionName, "")
End Get
End Property
 
Public ReadOnly Property IsConnected() As Boolean
Get
Return m_connected
End Get
End Property
 
Public Function Connect(ByVal connection As String) As Integer
Dim temp As Integer = 0
Dim INTERNET_AUTO_DIAL_UNATTENDED As UInteger = 2
Dim retVal As Integer = RAS.InternetDial(IntPtr.Zero, connection, INTERNET_AUTO_DIAL_UNATTENDED, temp, 0)
Return retVal
End Function
 
Public Sub Disonnect(ByVal connection As String)
RAS.RasHangUp(m_ConnectedRasHandle)
End Sub
 
End Class
 

End Namespace

Appreciate any help posible Dead | X|
GeneralYou got 5 PinmemberDavid Bazan9:00 26 Feb '08  
GeneralCant disconnect neither get ANY exception PinmemberMuammar©2:30 16 Mar '07  
GeneralProblem in Getting Duration Pinmemberss_hellhound6:06 16 Jan '06  
GeneralI LOVE YOU Pinmembernaiemk20:02 21 Oct '05  
GeneralQuestion about Improvement of RASDisplay class PinmemberJonny Depp22:27 10 Aug '05  
GeneralError 691 Pinmembersgomcres23:06 8 Sep '04  
GeneralRe: Error 691 PinmemberAhmad Maatouki10:50 9 Jan '07  
GeneralNeed help! PinmemberRockman X723:42 24 Aug '04  
GeneralHook to dos window PinmemberFrank59712:35 6 Aug '04  
GeneralUse of same Pinmemberdaniel doran5:27 10 Jun '04  
GeneralRasEnumConnections Error Pinmemberbsargos9:44 31 Jan '04  
GeneralRe: RasEnumConnections Error PinmemberMember 26767552:07 18 Apr '08  
QuestionVery well but problem with win98? Pinsussarmink3:11 30 Jan '04  
GeneralGood job. Two questions : Pinmemberbsargos13:47 29 Jan '04  
GeneralNeed a small help.... Pinmemberarun_br0:17 8 Dec '03  
GeneralDial-UP connectio Pinmemberhzzz12:48 7 Dec '03  
GeneralRe: Dial-UP connectio Pinmemberbenoityip2:33 8 Dec '03  
Questiongot this error...any ideas??? Pinmemberavla23:18 25 Nov '03  
GeneralCRITICAL error when reusing object : no disconnect PinmemberUps1016:31 16 Oct '03  
GeneralRe: CRITICAL error when reusing object : no disconnect PinmemberUps1016:04 20 Oct '03  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web01 | 2.5.120529.1 | Last Updated 7 Jul 2003
Article Copyright 2003 by Dan_P
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid