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