+ All Categories
Home > Documents > Mobilized .NET* Applications · offline mode, pre-fetch that data and then cache it. With this...

Mobilized .NET* Applications · offline mode, pre-fetch that data and then cache it. With this...

Date post: 21-May-2020
Category:
Upload: others
View: 2 times
Download: 0 times
Share this document with a friend
24
Mobilized .NET* Applications by Clayne B. Robison August 28, 2004
Transcript

Mobilized .NET* Applications by Clayne B. Robison August 28, 2004

The information contained in this document is provided for informational purposes only and represents the current view of Intel Corporation Intel on the date of publication. Intel makes no commitment to update the information contained in this document, and Intel reserves the right to make changes at any time, without notice. DISCLAIMER. THIS DOCUMENT AND ALL INFORMATION CONTAINED HEREIN IS PROVIDED AS IS. INTEL MAKES NO REPRESENTATIONS OF ANY KIND WITH RESPECT TO PRODUCTS REFERENCED HEREIN, WHETHER SUCH PRODUCTS ARE THOSE OF INTEL OR THIRD PARTIES. INTEL EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, IMPLIED OR EXPRESS, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND ANY WARRANTY ARISING OUT OF THE INFORMATION CONTAINED HEREIN, INCLUDING WITHOUT LIMITATION, ANY PRODUCTS, SPECIFICATIONS, OR OTHER MATERIALS REFERENCED HEREIN. INTEL DOES NOT WARRANT THAT THIS DOCUMENT OR THE INFORMATION CONTAINED HEREIN IS FREE FROM ERRORS, OR THAT ANY PRODUCTS OR OTHER TECHNOLOGY DEVELOPED IN CONFORMANCE WITH THIS DOCUMENT WILL PERFORM IN THE INTENDED MANNER, OR WILL BE FREE FROM INFRINGEMENT OF THIRD PARTY PROPRIETARY RIGHTS, AND INTEL DISCLAIMS ALL LIABILITY THEREFOR. INTEL DOES NOT WARRANT THAT ANY PRODUCT REFERENCED HEREIN OR ANY PRODUCT OR TECHNOLOGY DEVELOPED IN RELIANCE UPON THIS DOCUMENT, IN WHOLE OR IN PART, WILL BE SUFFICIENT, ACCURATE, RELIABLE, COMPLETE, FREE FROM DEFECTS OR SAFE FOR ITS INTENDED PURPOSE, AND HEREBY DISCLAIMS ALL LIABILITIES THEREFOR. ANY PERSON MAKING, USING OR SELLING SUCH PRODUCT OR TECHNOLOGY DOES SO AT HIS OR HER OWN RISK. Licenses may be required. Intel and others may have patents or pending patent applications, trademarks, copyrights or other intellectual proprietary rights covering subject matter contained or described in this document. No license, express, implied, by estoppels or otherwise, to any intellectual property rights of Intel or any other party is granted herein. It is your responsibility to seek licenses for such intellectual property rights from Intel and others where appropriate. Limited License Grant. Intel hereby grants you a limited copyright license to copy this document for your use and internal distribution only. You may not distribute this document externally, in whole or in part, to any other person or entity. LIMITED LIABILITY. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO YOU OR TO ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF YOUR USE OF THIS DOCUMENT OR RELIANCE UPON THE INFORMATION CONTAINED HEREIN, UNDER ANY CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY LIMITED REMEDY. Intel, the Intel logo, Pentium, Intel Xeon, and VTune are trademarks or registered trademarks of Intel Corporation or its subsidiaries in the United States and other countries. *Other names and brands may be claimed as the property of others. Copyright © 2005 Intel Corporation

Introduction

While much research has been done to determine the best nat ive Windows* APIs to use, l i t t le has

been done to assist developers in adapting their distr ibuted .NET* Framework-based appl icat ions for

mobi le environments. In this paper, we present sample methods to obtain system network

connection information using the classes found in the .NET Framework. The in it ia l intention is to

enable indiv idual appl icat ions to get this information on their own—the laissez-faire approach. But

the hope is that these methods wi l l eventual ly be used by a system-wide mobi l i ty-aware

infrastructure that wi l l in turn make the information more accessible to subscribing appl icat ions.

For this paper, we looked specif ical ly at version 1.1 of the .NET Framework running on desktop and

laptop systems. Note that this does not include appl ications running on the .NET Compact

Framework, although some of the same methods may apply. When working within the .NET

Framework, we can access the information to provide mobi l i ty awareness via three interfaces:

1. The Common Language Runtime (CLR) API;

2. The Windows Management Instrumentat ion (WMI) API; and

3. The native Windows API.

Inasmuch as the .NET Framework is essential ly a wrapper for the nat ive Windows API, and inasmuch

as the CLR System.Management namespace provides a CLR interface to WMI, this dist inct ion

between APIs is given for the sake of those appl ications that for one reason or another are l imited in

what they can do outside of the .NET Framework sandbox.

What makes an Application ‘Mobilized’?

An appl icat ion that is aware of mobi l i ty has the abi l i ty to funct ion smoothly ( i .e. maintain or increase

user productiv i ty) in a mobi le environment. An appl icat ion that can funct ion in a mobi le environment

is one that is aware enough of power, network, and sleep state that i t can free the user f rom care

about these uniquely mobi le states. The user can then focus instead on tasks directly re lated to

productiv i ty.

Typical ly, a mobi le aware appl ication provides four capabi l i t ies:

• Off l ine Data Management

• Seamless Connectivi ty

• Mult iple Platform Support

• Power & Performance Management

Offline Data Management

An appl icat ion that provides off l ine data management makes distr ibuted data avai lable off l ine. For

example, a database appl icat ion that provides this capabi l i ty, al lows a mobi le user access to

relevant data even when working off l ine. The management of this of f l ine data impl ies the abi l i ty to

synchronize changes made to the data whi le in an off l ine mode with the central data repository.

A system that provides of f l ine data management needs the abi l i ty to predict what a user wi l l need in

off l ine mode, pre-fetch that data and then cache i t . With this off l ine data, the appl icat ion can

emulate an on-l ine state, al lowing the user to be as productive as i f the main copy of the data were

avai lable. Once the user reconnects to the network, the two copies of the data must be reconci led

through a synchronizat ion process. Thus, making data avai lable off l ine is simple; but managing that

data and maintaining coherency is the more signif icant problem.

Seamless Connectivity

Software that provides seamless connectivi ty enables the user to never worry about connection

state. This might be as simple as detecting the presence of a route to the server, or choosing

between mult iple service providers and then establ ishing a connection. The goal is to al low the user

to spend more t ime on real work, not on network management. Once a connection to the server is

detected, the software senses the rate at which data can be transferred and makes inte l l igent

decisions based on that data rate. For example, upon reconnect to a network an appl icat ion wi l l

automatical ly start the synchronizat ion process without requir ing user intervention.

Multiple Platform Support

Mult ip le platform support in this case refers not only to operating system platforms, but a lso to the

mult iple hardware platforms for which an appl icat ion can be wr it ten, for example, laptop, PDA,

smart phone, cel l phone, etc. Ideal ly, the user’s experience on each of these devices is ident ical,

and there should be no need to re- learn the basic appl icat ion funct ional i ty.

Power & Performance Management

A mobi l ized appl icat ion is power f r iendly, and recognizes that battery, unl ike AC, is a l imited

resource and should be conserved when possible. Like other l imited resources, usage should

become more restr icted as the threat of resource exhaust ion become eminent. For example,

background threads and non-essentia l functional i ty, can be prior i t ized and postponed unti l power is

more plent i fu l .

Also, atomic operations that should be completed once they have started (e.g. burning a CD) should

f i rst ensure that suf f ic ient battery power remains for the task to complete.

Laissez-Faire Awareness vs. System Level Awareness vs. Adaptive Systems

Once this kind of mobi l ized software capabi l i ty is avai lable on a system, what happens when

mult iple appl icat ions request the information? Some information required to be aware of mobi l i ty is

process specif ic, and is system-wide. Should each appl icat ion be responsible for monitor ing system

connectiv i ty state, or should appl icat ions subscribe to that information from a system service?

On the one end of the spectrum, a la issez-fai re approach to mobi le enabl ing al lows each appl icat ion

to obtain the information i t needs. This approach requires the most modif icat ion at the appl icat ion

layer, but requires no mobi l i ty awareness in the underly ing system. However, when mult iple

appl icat ions need the same information, this approach is ineff ic ient.

I f a l l information for mobi le awareness is provided at the system level, appl icat ions ideal ly can

continue funct ioning as a lways connected systems because the mobi le sub-system completely

abstracts connection state from appl icat ions. In this model, appl icat ions must surrender control of

information to a central broker, but there is dupl ic i tous information gathering

In between these models is the archi tecture in which appl icat ions can subscribe as needed to the

information that a mobi l i ty subsystem publ ishes. Appl icat ions are aware of mobi l i ty, but they are not

completely responsible for adapting to i t . This architecture makes the best use of system resources

whi le al lowing the greatest f lexibi l i ty at the appl icat ion layer.

Laissez-Faire• Entirely responsible for adaptation• No support from operating system

Laissez-Faire• Entirely responsible for adaptation• No support from operating system

Application Awareness• Aware of the adaptive capabilities of the system• Changes its behavior accordingly

Adaptive• Underlying system is totally responsible• Applications run unmodified

Adaptive• Underlying system is totally responsible• Applications run unmodified

Tran

spar

ency

Figure 1: Mobi le Environment Transparency

Network Connection Awareness

Information about the path between cl ient and server is cr i t ical for appl icat ions that provide

seamless transit ions between connected and unconnected states. We’l l use the classes in the

System.Net and System.Net.Sockets namespaces to i l lustrate how to get that information.

IPEndPoint Visibility

The f i rst quest ion that we need to ask before transferr ing data to or f rom a remote system is “ Is the

service on my target machine vis ible?” This means knowing not only the IP address of the machine,

but the port number on which a server is l istening.1 For a Web-Service, this port would be either 80

for unencrypted traff ic or 443 for SSL traff ic.

1 These two pieces of data—IP Address and Port number—are encapsulated in the

System.Net. IPEndPoint class, hence the section heading “IPEndPoint Visibi l i ty.”

CLR

One way of determining the vis ibi l i ty of our service is simply to attempt a connection to i t . I f i t

works, we can see i t. I f we get an error, we can use the error code to f ind out why we can’t see i t .

Using the Connect( ) method of the Sockets class2, i t might look l ike this:

Figure 2: Establ ishing a Connection

try { s.Connect(ipEndPoint); bEndPointVisible = true; //If no exception is thrown, we have a connection bEndPointVisible = true; } catch(SocketException se) { bEndPointVisible = false; //figure out what the problem was switch ( se.ErrorCode ) { case 10165: //... } }

Using the error codes, we can determine what the problem is.

Table 1: Possible Error Codes for the Socket.Connect( ) method.

Error code Meaning

WSANOTINITIALISED A successful WSAStar tup cal l must occur before using this funct ion.

WSAENETDOWN The network subsystem has fai led.

WSAEADDRINUSE The socket's local address is al ready in use and the socket was not

marked to al low address reuse with SO_REUSEADDR. This error usual ly

occurs when executing b ind, but could be delayed unti l th is funct ion i f the

b ind was to a part ia l ly wi ldcard address ( involv ing ADDR_ANY) and i f a

speci f ic address needs to be committed at the t ime of this funct ion.

WSAEINTR The blocking Windows Socket 1.1 cal l was canceled through

WSACance lB lock ingCa l l .

2 The CLR also provides TCPClient and UDPClient c lasses that further simpl i fy the use of these

protocols. Our discussion here focuses on Sockets, but the same methodology can be used in these

classes as wel l .

Error code Meaning

WSAEINPROGRESS A blocking Windows Sockets 1.1 cal l is in progress, or the service

provider is st i l l processing a cal lback funct ion.

WSAEALREADY A nonblocking connect cal l is in progress on the specif ied socket.

Note In order to preserve backward compatibi l i ty, th is error is reported

as WSAEINVAL to Windows Sockets 1.1 appl icat ions that l ink to either

Winsock.dl l or Wsock32.dl l .

WSAEADDRNOTAVAIL The remote address is not a val id address (such as ADDR_ANY).

WSAEAFNOSUPPORT Addresses in the specif ied family cannot be used with this socket.

WSAECONNREFUSED The attempt to connect was forceful ly rejected.

WSAEFAULT The name or the namelen parameter is not a val id part of the user address

space, the namelen parameter is too smal l , or the name parameter

contains incorrect address format for the associated address family.

WSAEINVAL The parameter s is a l istening socket.

WSAEISCONN The socket is already connected (connection-or iented sockets only).

WSAENETUNREACH The network cannot be reached from this host at th is t ime.

WSAENOBUFS No buffer space is avai lable. The socket cannot be connected.

WSAENOTSOCK The descriptor is not a socket.

WSAETIMEDOUT Attempt to connect t imed out without establ ishing a connection.

WSAEWOULDBLOCK The socket is marked as nonblocking and the connection cannot be

completed immediately.

WSAEACCES Attempt to connect datagram socket to broadcast address fai led because

se tsockopt option SO_BROADCAST is not enabled.

Advantages to this method are 1) i f the connection is successfu l, the socket is ready for use; and 2)

the SocketExecption.ErrorCode property can give useful information about the cause of the error. I f

the server is avai lable, the cal l can return almost immediately; but i f the server is not avai lable, the

cal l can take up to 20 seconds before i t t imes out and throws an exception. For this reason, i t may

be best to use the asynchronous Socket.BeginConnect( ) cal l ; but even so, i t wi l l take up to 20

seconds in order to ver i fy that the service is not vis ible.

Another method of using the Sockets class to detect remote system vis ibi l i ty is to send ICMP

packets across the network to the remote machine ( i .e. ‘ping’ the remote system). This method,

however, at best can only determine whether a remote machine is on the network, and does not

guarantee the vis ibi l i ty of the target service on that machine. Another problem with using ICMP to

determine remote system vis ibi l i ty is that the packets are not guaranteed to reach the server. Even

for appl icat ions that run inside a f i rewal l (or through VPN tunnels) corporate IT pol ic ies may not

al low ICMP traff ic to be forwarded. Because of these disadvantages, we won’t take the t ime to

demonstrate custom ‘ping’ communicat ion in this art ic le.

WMI

The root/Cimv2 namespace provides two classes that al low us to determine whether an appl icat ion

is running on a remote system. I f the appl icat ion is a registered Windows service, i t can be found by

querying the WMI database for Win32_Service objects. I f the “Status” property of our target service

is equal to “Running”, our service is running. Running processes that are not registered Windows

services can be discovered using the Win32_Process class. However, nei ther of these methods

al low us to determine whether our target appl icat ion is ready to receive or send data. Nor does this

method work when the requestor does not have suf f ic ient access priv i leges on the WMI database—a

most l ikely si tuation.

Provided the user has suf f ic ient r ights on their own system, we can use the Win32_PingStatus class

that is avai lable on Windows XP and Windows Server 2003 to determine the vis ibi l i ty of a remote

machine. Obtaining an instance of this class is analogous to executing the “ping” ut i l i ty from a

command l ine. For example:

Figure 3: Using WMI to ‘Ping’ a remote machine

ManagementObjectSearcher mos = new ManagementObjectSearcher ("root\\CimV2", string.Format("SELECT * FROM Win32_PingStatus " "WHERE Address=\"{0}\"", strIPAddress)); foreach ( ManagementObject mo in mos.Get() ) { // MgmtClassGen.exe generated class PingStatus ps = new PingStatus(mo); switch (ps.StatusCode) { case PingStatus.StatusCodeValues.Success: //do stuff //... } }

This directs the WMI ping provider to send an ICMP packet to the machine at address str IPAddress.

The disadvantages of using ICMP are discussed above.

Windows API

By cal l ing into the unmanaged Windows API, we can take advantage of numerous funct ions that can

help us determine the vis ibi l i ty of a remote machine. Especial ly helpful are the funct ions in the IP

Helper API found in the Platform SDK. The GetBestInterface funct ion tel ls us the index of the best

interface to use to reach a specif ied address:

Figure 4: Using the GetBestInterface Function

DWORD dwBestIf Index = 0xFFFF;

DWORD retVal = GetBestInterface( inet_addr(szIPAddr) , &dwBestIf Index);

i f ( retVal == NO_ERROR )

{

pr intf ("Best Interface to IP Address %s = %x.",

szIPAddr, dwBestI f Index);

}

else

{

pr intf ("Error Occured: %x .", retVal ) ;

}

When the dest ination machine is v is ib le, NO_ERROR is returned and the interface index is val id;

when no network interface is present, this funct ion returns an error. But when an interface is

present, this funct ion can produce a false posit ive: the return value is NO_ERROR and the Index

number is val id even though the remote machine is not v is ible. In addit ion to being somewhat

unrel iable, as is the case with ICMP, most of these functions can only help us determine whether a

remote machine is avai lable and do not al low us to determine whether an appl icat ion is running on

that machine.

IPEndPoint Visibility Changes

The next two quest ions that distr ibuted appl icat ion developers must ask are related to changes in

the vis ibi l i ty of IPEndPoints: “How can I tel l i f my remote system is no longer avai lable so I can stop

trying to transfer data to i t?” and “How can I tel l i f my remote system has appeared so I can start

communicat ing with i t?” I f we combine these two questions with the two possible data transfer

situations that we might be in at any t ime—we are either transferr ing data, or we aren’t—we come

up with a matr ix:

Currently Transferr ing Data?

IPEndPoint Change Type Yes No

Appearance Irrelevant Relevant

Disappearance Relevant Irrelevant

Logical ly, only two of these situat ions are relevant. I f we are current ly transferr ing data, the sudden

appearance of our target IP EndPoint is not l ikely: we are current ly transferr ing data to/from i t.

However, we do want to know whether i t has disappeared. Conversely, i f we are not current ly

transferr ing data, we probably don’t care whether our target EndPoint disappears. However, we

might get data to send, and therefore we want to be noti f ied when an EndPoint becomes vis ible.

CLR

In real i ty, what we are looking for in the f i rst s i tuat ion is an event to not i fy us that the EndPoint to

which we are currently transferr ing information is no longer vis ible. No such event exists as such in

the CLR, but we could certainly rol l our own using the SocketException that gets thrown when our

act ive Socket.Send() or Socket.Receive() cal l is disconnected3:

F igure 5: Using SocketException to Detect IP Endpoint Disappearance

Socket s = new Socket(...); //Establish Socket connection try { bConnected = true; s.Send(sBuffer); s.Receive(rBuffer); } catch(SocketException se) { bConnected = false; //determine what went wrong switch( se.ErrorCode ) { case 10165: //... }

}

3 Assuming we are using a connection-oriented protocol l ike TCP.

Regarding the answer to the second quest ion—has my remote service appeared?—it would be nice

i f we could register for an event to noti fy us when our IPEndPoint was avai lable. Here’s our event

handler:

F igure 6: Our EndPoint Avai lable Event Handler

//This method gets called when our IPEndPoint is available public void EndPointAvailableEventHandler ( EndPointAvailableEventArgs args ) { //args contains the connected socket args.getSocket().Send(…); }

Here’s the method we cal l to register for the event:

Figure 7: Register ing for the EndPoint Avai lable Event

//Call this to register for the IPEndPointAvailable event public void NotifyIPEndPointAvailable( IPEndPoint RemoteEndPoint, EndPointAvailableEventHandler callbackFunction ) { this.m_remoteEndPoint = RemoteEndPoint; this.m_callbackFunction = callbackFunction; }

After we’ve registered, we send the monitor thread going and wait for not i f icat ion:

Figure 8: Pol l ing for Connection State

//Call this from a separate thread public void PollForEndPoint(int iPollingInterval) { bool bConnected = false; while ( m_bAlive && !bConnected ) { //make sure we start out disconnected Socket s = new Socket (...); try { s.Connect( m_remoteEndPoint ); if( this.m_callbackFunction != null ) { m_callbackFunction( new EndPointAvailableEventArgs( s ) ); } bConnected = true; } catch (SocketException se ) { Thread.Sleep( iPollingInterval ); //try again in a bit } } }

The advantage of this method is that we know for sure that the service on our remote machine (and

not just the machine) is e ither up or down. The disadvantage is that we have to tweak the Socket

object in order to get the status change information within a reasonable amount of t ime. By

tweaking the send and receive buffer sizes, and by turning off the Nagle algori thm, we can be

noti f ied a lmost immediate ly when our service disappears in the middle of a transfer, but we do

sacri f ice some network eff ic iency. And to get the same immediacy on our service appearance event,

we real ly should use the asynchronous BeginConnect( ) method and t imeout sooner than the sockets

sub-system default:

F igure 9: Tweaking the Connection Timeout

//Cal l th is f rom a separate thread

publ ic void Pol lForEndPoint( int iPol l ingInterval, int iTimeOut)

{

bool bConnected = false;

whi le ( m_bAl ive && !bConnected )

{

try

{

//WaitOne() cal ls must block unt i l Set( ) is cal led

m_autoResetEvent.Reset( ) ;

Socket s = new Socket(. . . ) ;

//Delegate the blocking connection

//cal l to another thread

s.BeginConnect( remoteEndPoint,

new AsyncCal lback( myAsyncConnectionCal lback ) ,

s ) ; //Give that thread our socket object

//Give the other thread 5 seconds to make a connection

i f ( m_autoResetEvent.WaitOne( iTimeOut, fa lse ) )

{

//The socket connected in t ime:

//we have a val id socket

i f ( th is.m_cal lbackFunction != nul l )

{

m_cal lbackFunction(

new EndPointAvai lableEventArgs( s ) ) ;

}

bConnected = true;

}

e lse

{

//We t imed out and we don't have a val id socket

// try again in a bit

Thread.Sleep( iPol l ingInterval ) ;

}

}

catch (SocketException se )

{

//Figure out what happened

}

}

}

WMI

The MSNdis_StatusMediaConnect event in the root/WMI namespace is theoret ical ly generated

whenever an NDIS adapter’s media moves from a disconnected to a connected state (e.g. when the

Ethernet cable is plugged in, or when the Wireless card detects a signal ) . However, aside from the

fact that the event is not completely rel iable ( i t doesn’t detect the appearance of PPP adapters at

al l ) , the event is generated before any protocol binding takes place and real work can be done. This

is f ine in environments where the protocol binding fol lows closely on the heels of the media

connection (e.g. environments with stat ic IP addresses), but the event can be only used as a cue in

environments where the protocol binging lags behind the media connections (e.g. DHCP

environments). This method also does not guarantee IP EndPoint avai labi l i ty—only the existence of a

media l ink between the local system and its nearest network node.

The MSNdis_StatusMediaDisconnect event detects when an NDIS adapter’s media moves from a

connected to a disconnected state. This is a more useful (a lbei t just as unrel iable) an event because

one can guarantee that i f the media is disconnected, the protocol is also unbound, and the IP

EndPoint on the other end of the pipe is no longer vis ible. Hence, register ing for the

MSNdis_StatusMediaDisconnect event can be useful when we are transferr ing data and want to

know when the connection disappears.

I f we use MgmtClassGen.exe to generate a C# wrapper for the MSNdis_StatusMediaDisconnect

event, register ing for the MSNdis events in C# looks l ike this:

Figure 10: Register ing for the Event

try { //query WMI for the event watcher m_MediaDisconnectWatcher = new ManagementEventWatcher("root\\wmi", "SELECT * FROM MSNdis_StatusMediaDisconnect"); // Register for the event m_MediaDisconnectWatcher.EventArrived += new EventArrivedEventHandler( this.MediaDisconnectEventHandler); //start the event thread m_MediaDisconnectWatcher.Start(); } catch (ManagementException me) { if ( m_WMIDisconnectWatcher != null ) { m_WMIDisconnectWatcher.Stop(); m_WMIDisconnectWatcher= null; } }

Figure 11: The Event Handler

public void MediaDisconnectEventHandler(object o, EventArrivedEventArgs e) { //Use the NewEvent property to make a //StatusMediaDisconnect object StatusMediaDisconnect smd = new StatusMediaDisconnect(e.NewEvent); //figure out which adapter was disconnected string strDisconnectedAdapterName = smd.InstanceName; //... }

Effective Data Rate

The effect ive data rate refers to the speed at which real data is being transferred to a remote IP

Endpoint. On an Ethernet connection with a l ink speed of 100 Mbps, in the unl ikely event that there

were no transport overhead or packet col l is ions, the best effective data rate would be 12.5 MBps.

Link speed, l ike the speed l imit on an interstate f reeway, is useful in determining the ideal nature of

the immediate segment of a journey; but i t is not very helpful when there is a lot of traff ic, and when

the segment beyond our immediate ken has a much lower speed l imit.

CLR

As with IP EndPoint information, the Socket class provides al l the information we need to calculate

the effect ive data rate of our connection. I f we extend the Socket class with a DataRateAwareSocket

class, we can easi ly track how many bytes are transferred, and how long i t takes to transfer them.

For example:

Figure12: A DataRateAwareSocket Send() method

//Our new Send method public new int Send (byte[] buffer) { DateTime start = DateTime.Now; //Start the clock int retVal = base.Send( buffer ); DateTime stop = DateTime.Now; //stop the clock TimeSpan elapsedTime = stop - start; double rate = (double)retVal / elapsedTime.TotalSeconds; Monitor.Enter( m_dCumulativeSendRate ); //Synchronize access //BAD algorithm, but you get the idea m_dCumulativeSendRate = ( m_dCumulativeSendRate + rate ) / 2; Monitor.Exit( m_dCumulativeSendRate ); return retVal; } public double SendRate { get { //Calculation is already done, just return the value

double retVal; Monitor.Enter( m_dCumulativeSendRate ); retVal = m_dCumulativeSendRate; Monitor.Exit( m_dCumulativeSendRate ); return retVal; } }

We can make the data transferr ing threads more eff ic ient i f we just accumulate the bytes transferred

in the transfer operat ion and perform calculat ions only when they the query ing thread wants the data

rate:

Figure 13: A More Eff ic ient Method

//more efficient public new int Send (byte[] buffer) { int retVal = base.Send( buffer ); TotalSentBytes += retVal; return retVal; } //Don't call this on the same thread that is sending data! public double SampleSendRate(TimeSpan sampleLength) { int iStartByteCount = TotalSentBytes; //sleep while data is sent Thread.Sleep(sampleLength); int iEndByteCount = TotalSentBytes; int iSentBytes = iEndByteCount - iStartByteCount; //rate = bytes/second return iSentBytes / sampleLength.TotalSeconds; }

Because we have more than one thread using the TotalBytes property, we need to make it thread-

safe:

Figure 14: Our Thread-safe TotalBytes Property

//The object we are going to synchronize on must be a reference type private Int32 m_iTotalSentBytes = new Int32(); //allow threadsafe access private int TotalSentBytes { get { int retVal; Monitor.Enter( m_iTotalSentBytes ); //Synchronize access retVal = m_iTotalSentBytes; Monitor.Exit( m_iTotalSentBytes ); return retVal; } set

{ Monitor.Enter( m_iTotalSentBytes ); //Synchronize access m_iTotalSentBytes += value; Monitor.Exit( m_iTotalSentBytes ); } }

A few caveats here. Fi rst, th is method does introduce some sampl ing overhead, compounded by our

use of synchronizat ion objects. Second, because of the Nagle a lgor i thm4 and by the size of

underlying send buffer, our Send() method above may return before the data is actual ly sent across

the network media. One work around would be to disable the Nagle algorithm and optimize the send

buffer s ize whi le sampl ing is taking place; this, of course, would mean that the sampled data rate is

not a completely accurate measure of the effective data rate.

Final ly, as is the case with road traff ic, i t would be nice to know the effect ive data rate before we

start transferr ing data. The method above, however, requires at least some data to be transferred

before a measurement can be taken. Since that is probably what we are try ing to do anyway, this is

no big deal. Should the data rate be too slow for an effective transfer, we can abort the process; i f

our distr ibuted appl icat ion has the abi l i ty to resume the transfer, we have at lease made forward

progress whi le determining our data rate.

We can work around some of these problems by creating our own ping funct ional i ty using sockets.

This would al leviate the sampl ing overhead and al low us to est imate the effect ive data rate between

us and our target machine before we transfer any of our own data. However, because network traff ic

requires system resources that may be constrained, and because ICMP repl ies can be generated by

network hardware and drivers, this method is guaranteed to ref lect the working state of the remote

system on the data rate. And, of course, this method is useless in ICMP-unfr iendly network

environments.

WMI

I f we real ly want to use ICMP, using the Win32_PingStatus object is much simpler. I f we modify the

WQL query we used above to include a buffer s ize, we can t ime the

ManagementObjectSearcher.Get( ) method cal l to see how long it took to get a response:

Figure 15: Using a Win32_PingStatus Object to Est imate Effective Data Rate

ManagementObjectSearcher mos = new ManagementObjectSearcher ( "root\\CimV2", string.Format("SELECT * FROM Win32_PingStatus " "WHERE Address=\"{0}\" AND BufferSize={1}", strIPAddress, iBufferSize ) );

4 See Jones, Anthony and Jim Ohlund, Network Programming for Microsoft Windows, p. 303-304 for

more information on the Nagle Algori thm.

this.StartClock(); ManagementObjectCollection moc = mos.Get(); this.StopClock(); foreach ( ManagementObject mo in moc ) { //Class generated by MgmtClassGen.exe PingStatus ps = new PingStatus(mo); if ( ps.StatusCode == PingStatus.StatusCodeValues.Success ) { UInt32 uiByteCount = ps.ReplySize + ps.BufferSize; double rate = uiByteCount/this.ElapsedTime.TotalSeconds; //Alternatively, use the ResponseTime property of //PingStatus //double rate = uiByteCount/ps.ResponseTime; //ICMP send and reply are sequential; //we want a full-duplex data rate //Assuming that traffic is flowing //the same speed in both directions double fullDuplexRate = rate * 2; } }

As mentioned above, using the ICMP protocol to determine our effective data rate doesn’t require

us to send any of our own data in order to determine the transfer rate, and there is no sampling

overhead. Using WMI to access the information that ICMP can provide al lows us the same

funct ional i ty as our own ICMP sockets implementat ion, without al l of the coding/val idat ion overhead.

But we are t ied to the platforms that support the Win32_Ping Status c lass5.

Effective Data Rate Changes

I f we can detect changes in the effect ive data rate between two endpoints, then users can subscribe

to high and low thresholds and we can noti fy them when these thresholds are crossed. The two

most l ikely uses of this information are: 1) An appl icat ion has a large transfer that i t does not want

to begin unti l the Effect ive data rate to i ts target endpoint r ises above a certain threshold; and 2) an

appl icat ion that is current ly transferr ing data wishes to be noti f ied when the effective data rate of

the transfer drops below a certain threshold. Notice that for the f i rst scenario, non-appl icat ion data

must be used to measure the data rate because the user wants the effect ive data rate in order to

begin a transfer. In the second scenario, however, the appl icat ion specif ic data can be used to

measure the data rate. Therefore, our discussion needs to answer the quest ion in two scenarios:

when a transfer is already taking place, and when a transfer is pending.

5 At the t ime of wri t ing, Microsoft Windows XP, and Microsoft Windows Server 2003.

CLR

When data is already being transferred, we can use the Send() and Receive() methods on the

extended Socket( ) c lass i l lustrated above to track the data rate. Let’s provide delegates and

threshold subscript ion methods:

Figure 16: A Sample Threshold Subscr ipt ion Method

//The threshold event delegate public delegate void DataRateThresholdEventHandler( object sender, DataRateThresholdEventArgs e); public DataRateAwareSocket: Socket { //.... protected double m_dSendLowThreshold;// KB/sec protected event DataRateThresholdEventHandler SendDataRateLowThresholdEvent; //.... //Allow them to subscribe to the event and specify a threshold public void SubscribeSendRateBelowThreshold( double dKBytesPerSecond, DataRateThresholdEventHandler eventHandler) { this.SendDataRateLowThresholdEvent += eventHandler; this.m_dSendLowThreshold = dKBytesPerSecond ; } }

We then begin our own thread to use the SampleSendRate() method we def ined above, compare the

rate with the threshold, and noti fy the user when the data rate crosses the threshold:

Figure 17: Sample, Evaluate, and Noti fy

//Don't call on the same thread that is sending protected void SampleAndEvaluateSendRate() { while (m_bAlive) { //sample the send rate double rate = this.SampleSendRate( new TimeSpan( 0,0,0,0, this.m_iSampleLength ) ); //if it is below the send threshold, raise an event if ( rate < this.m_dSendLowThreshold ) { if ( this.SendDataRateLowThresholdEvent != null ) { SendDataRateLowThresholdEvent( this, new DataRateThresholdEventArgs( rate ) ); } } Thread.Sleep(this.m_iPollingInterval); } }

I f we need not i f icat ion that the data rate has r isen above a threshold before we transfer data, we

have to be a l i t t le more creat ive. Because we logical ly have to transfer some data in order to

calculate a data rate greater than 0, we have two choices:

Transfer non-appl icat ion data, or

Transfer appl icat ion data.

A good choice for non-appl ication data is ICMP data. To do this, we modify our SampleSendRate( )

method above to use e ither our custom Socket ICMP functional i ty, or the WMI Win32_PingStatus

class. Another option would be to in ject traff ic measuring data into the sockets that have already

been establ ished, but that would require the receiver to have the abi l i ty to f i l ter out and discard

non-appl ication traf f ic.

However, i f we have the option to use appl icat ion data in our SampleSendRate() method, noti fy ing

subscribers that the data rate has r isen above a threshold simply involves reversing the logic of the

SampleAndEvaluateSendRate() method above.

Adapter Selection

One f inal considerat ion remains with regard to enabl ing .NET based appl icat ions to function ideal ly

in the mobi le network environment. When there is more than one act ive network adapter in the

system, how do we determine which is the best one? In most si tuations would come down to which

connection has the highest effective data rate, and for many appl ications, the best solut ion may be

to bind to and ut i l ize a l l avai lable local IP addresses that can see a remote endpoint. But there may

be more considerat ions such as the existence IPSec or other securi ty mechanism on the connection,

and in some situations, a WLAN connection may be more desirable (because i t is persistent between

desk and meeting room) than a LAN connection, even though the latter has the better data rate.

Socket methods that are cal led without binding to a local IP address al low the underlying system to

determine the best connection, but i f the underlying system’s def in it ion of best connection

contradicts the appl icat ion’s def ini t ion, there needs to be a way to overr ide that choice using the

Socket.Bind() cal l 6. Obviously the def in i t ion of ‘best adapter’ is a system specif ic pol icy issue that is

beyond the scope of this paper, but mapping IP addresses to i ts under ly ing adapter is crucial to

making this kind of decis ion.

CLR

From within the CLR, the only information avai lable is the l ist of IP addresses provided in the

IPHostEntry class. These IP addresses can each be used in a Socket.Bind() cal l that wi l l b ind al l

subsequent socket cal ls to the adapter bound to that IP address. However, the CLR provides no

information about the underlying adapter.

6 And what of cl ients or servers that have mult ip le IP addresses al iased to the same adapter?

WMI

Using the root/cimv2 namespace’s Win32_NetworkAdapterConf igurat ion objects, we can take the IP

Address provided by the IPHostEntry class and f ind out which adapter i t is bound to7.

Windows

The IPHelper API in the Windows Platform SDK provides helpful methods to query the system route

and network adapter tables. This API also provides events that report changes to these tables.

Conclusion

In summary, in order for an appl icat ion to maximize user productiv i ty in the mobi le computing world,

i t must be aware and take advantage of network connection state. Mobi l ized software must be able

to detect and react to the vis ibi l i ty of target services, as wel l as changes in that v is ibi l i ty; i t must

also be able to determine the effect ive data rate to the remote service, as wel l as changes to that

data rate. In some instances, determining the mapping of IP addresses to underlying adapters is

also helpful in determining the best connection when there is a choice. Whi le there is some

information that cannot be obtained without using either the WMI or the Windows API, most of the

information required for network connection awareness can be gleaned using methods provided by

the CLR.

References

Jones, Anthony and Jim Ohlund, Network Programming for Microsoft Windows.

System.Net.Sockets namespace documentat ion:

http://msdn.microsoft.com/l ibrary/default.asp?url=/ l ibrary/en-

us/cpref/html/fr l r fsystemnetsockets.asp

System.Net namespace documentation:

http://msdn.microsoft.com/l ibrary/default.asp?url=/ l ibrary/en-us/cpref/html/ fr l r fSystemNet.asp

System.Management namespace documentat ion:

http://msdn.microsoft.com/l ibrary/default.asp?url=/ l ibrary/en-

us/cpref/html/fr l r fsystemmanagement.asp

The WMI Win32_PingStatus class: http://msdn.microsoft.com/l ibrary/defaul t.asp?url=/ l ibrary/en-

us/wmisdk/wmi/win32_pingstatus.asp

Using WMI to manage NDIS objects: http://www.ndis.com/faq/QA01050301/default.htm

7 The root/wmi namespace’s MSNdis_LinkSpeed object can provide information about the current

l ink speed of the adapters on the system.

Detecting internet connection state: http://www.ndis.com/faq/QA05040101.htm

NDIS events in WMI: http://msdn.microsoft.com/msdnmag/issues/02/08/SENS/default.aspx, and

http://msdn.microsoft.com/msdnmag/ issues/02/08/SENS/figures.asp#f ig5

Network Status Detect ion: http://www.intel .com/cd/ids/developer/asmo-na/eng/43917.htm

Intel® Mobi le Appl icat ions Architecture Guide, http://www.intel.com/cd/ids/developer/asmo-

na/eng/61193.htm

Developer Centers

Mobi l ized Software

Intel® Centr ino™ Mobi le Technology

.NET Platform

ter contained or described in this document. No licLimited License Grant. Intel hereby grants you a limited copyright license to copy this document for your use and internal distribution only. You may not distribute this document externally, in whole or in part, to any other person or entity.LIMITED LIABILITY. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO YOU OR TO ANY OTHER THIIntel, the Intel logo, Pentium, Intel Xeon, and VTune are trademarks or registered trademarks of Intel Corporation or its subsidiaries in the United States and other countries.*Other names and brands may be claimed as the property of others.Copyright © 2004 Intel Corporation The information contained in this document is provided for informationalx

as the property of others. Copyright © 2005 Intel Corporation


Recommended