Connection Management

Once you have created an active RAS connection to a remote server, you can use several functions provided by RAS to find out more information about current connections, device states, and connection properties.

To get information about what state a RAS connection is in, you can use the RasGetConnectStatus() function. This function is extremely versatile and can be used in a variety of situations:

  • RasDial() connections status. You can use the RasGetConnectStatus() function after RasDial() has completed to determine the status of the connection operation (either asynchronous or synchronous).

  • Use as a polling mechanism during synchronous RasDial(). To get the current state of a blocking RAS connection, the RasGetConnectStatus() function can be called from a separate thread while a synchronous RasDial connection is being established.

  • RasHangUp() status. Use RasGetConnectStatus() to ensure that you have received a RASCD_Disconnected status message from the RAS device before attempting to use it again.

  • Determine name and device type of an active connection. The RasGetConnectStatus() function can be used to determine the device name and type based on the RAS session handle.

The RasGetConnectStatus() function is defined as follows:

DWORD RasGetConnectStatus(HRASCONN rasconn,
   LPRASCONNSTATUS lprasconnstatus);

The first parameter, rasconn, should be the handle for the RAS connection for which you want the current status (which you have from the previous call to RasDial() or by using the RasEnumConnections() function). This is followed by a pointer to a RASCONNSTATUS structure that will receive the current status information. Remember to set the dwSize member of the lprasconnstatus structure to the size of RASCONNSTATUS in order for the function to work properly.

The RASCONNSTATUS structure is defined as follows:

typedef struct tagRASCONNSTATUS {
   DWORD dwSize;
   RASCONNSTATE rasconnstate;
   DWORD dwError;
   TCHAR szDeviceType[RAS_MaxDeviceType+1];
   TCHAR szDeviceName[RAS_MaxDeviceName+1];
} RASCONNSTATUS, *LPRASCONNSTATUS;

The first member is dwSize, which should be set to the size of the RASCONNSTATUS structure. This is followed by rasconnstate which will specify the current state of the connection process. The possible values for rasconnstate are listed in Table 6.2 (and are the same for asynchronous RasDial()). Next, dwError will contain a nonzero error code if the rasconnstate member has a state that signifies an error condition.

The last two values, szDeviceType and szDeviceName, are null-terminated strings that contain the device name and type.

Enumerating Connections

To get a list of all of the RAS connection handles that are currently active on your device, you can use the RasEnumConnections() function:

DWORD RasEnumConnections(LPRASCONN lprasconn, LPDWORD lpcb,
   LPDWORD lpcConnections);

The first parameter should point to a buffer that will receive the array of RASCONN structures, one for each active RAS connection. In order to use RasEnumConnections() properly, you must set the dwSize member of the first structure in the buffer to the size of RASCONN. This is followed by lpcb, a pointer to a DWORD value that contains the size, in bytes, of the lprasconn buffer you are passing in. Finally, lpcConnections should point to the actual number of bytes that were written to the lprasconn buffer when it returns.

The RASCONN structure is defined as follows:

typedef struct tagRASCONN {
   DWORD dwSize;
   HRASCONN hrasconn;
   TCHAR szEntryName[RAS_MaxEntryName+1];
} RASCONN, *LPRASCONN;

The structure contains three members: the size of the structure in bytes, the active connection handle, and the RAS phonebook entry name that corresponds to the connection handle.

To accurately determine how much memory you need to allocate in order to enumerate all of the active RAS connections, it can be useful to use the ERROR_BUFFER_TOO_SMALL error code. To do this, you would first call RasEnumConnections() to get the size required, and then call it a second time when you have a properly allocated buffer.

Connection Information

To obtain more information about the actual connection, such as the amount of time a RAS connection has been active, or the number of bytes that have been sent or received, you can use the RasGetLinkStatistics() function:

DWORD RasGetLinkStatistics(HRASCONN hRasConn, DWORD
   dwSubEntry, RAS_STATS *lpStatistics);

The first parameter is a handle to an active RAS connection. This is followed by dwSubEntry and should be set to 0. The last parameter is a pointer to a RAS_STATS structure that will receive the statistical information for the connection. Remember to set the dwSize member of the lpStatistics structure to the size of RAS_STATS before calling RasGetLinkStatistics().

The function will return a 0 value if it is successful, and will fill the lpStatistics buffer with all of the available connection data.

The RAS_STATS structure is defined as follows:

typedef struct _RAS_STATS {
   DWORD dwSize;
   DWORD dwBytesXmited;
   DWORD dwBytesRcved;
   DWORD dwFramesXmited;
   DWORD dwFramesRcved;
   DWORD dwCrcErr;
   DWORD dwTimeoutErr;
   DWORD dwAlignmentErr;
   DWORD dwHardwareOverrunErr;
   DWORD dwFramingErr;
   DWORD dwBufferOverrunErr;
   DWORD dwCompressionRatioIn;
   DWORD dwCompressionRatioOut;
   DWORD dwBps;
   DWORD dwConnectDuration;
} RAS_STATS, *PRAS_STATS;

Table 6.4 describes the RAS_STATS structure.

Table 6.4. RAS_STATS Flags

Member

Description

dwSize

Size of the RAS_STATS structure

dwBytesXmited

Number of bytes transmitted

dwBytesRcved

Number of bytes received

dwFramesXmited

Number of frames transmitted

dwFramesRcved

Number of frames received

dwCrcErr

Number of CRC errors that have occurred on this connection

dwTimeoutErr

Number of timeout errors that have occurred on this connection

dwAlignmentErr

Number of alignment errors that have occurred on this connection

dwHardwareOverrunErr

Number of hardware overruns that have occurred on this connection

dwFramingErr

Number of framing errors that have occurred on this connection

dwBufferOverrunErr

Number of buffer overruns that have occurred on this connection

dwCompressionRatioIn

Compression ratio for incoming data

dwCompressionRatioOut

Compression ratio for outgoing data

dwBps

Speed of the connection

dwConnectDuration

Amount of time, in milliseconds, that the connection has been active

NOTE:

The dwBps member of RAS_STATS specifies the determined speed of the remote connection that was negotiated upon connection to the remote server. If you want to calculate the actual network throughput of the connection, you can divide the number of bytes that have been sent over the connection (dwBytesXmited) and received (dwBytesRcved) by the amount of time that the connection has been active (dwConnectDuration).


To get any network-protocol-specific information (also known as network projection information) from a RAS server with which you have established a connection, you can call the RasGetProjectionInfo() function. As previously mentioned, Pocket PC supports only SLIP or PPP as the protocol for remote access connections. This limits the amount of network projection information that you can query to the IP address that the server has assigned to the device, as well as any other error information regarding the protocol. The function is defined as follows:

DWORD RasGetProjectionInfo(HRASCONN hRasConn, RASPROJECTION
  rasprojection, LPVOID lpprojection, LPDWORD lpcb);

The first parameter should be set to the RAS connection handle for which you want projection information. This can be the handle that was originally returned from RasDial(), or one obtained through the RasEnumConnections() function. Next, you must set the rasprojection parameter to RASP_PppIp.

The lpprojection parameter is a data structure that will receive your projection information. The structure, in the case of RASP_PppIP, is defined as follows:

typedef struct tagRASPPPIP {
   DWORD dwSize;
   DWORD dwError;
   TCHAR szIpAddress[RAS_MaxIpAddress+1];
   TCHAR szServerIPAddress[RAS_MaxIPAddress+1];
   DWORD dwOptions;
   DWORD dwServerOptions;
} RASPPPIP, *LPRASPPPIP;

The structure contains three basic members: the size of the structure, any PPP connection negotiation error codes, and the null-terminated string representing the client's IP address. As usual, you must first set the dwSize member to the size of RASPPPIP in order for the function to be called properly.

The final parameter in RasGetProjectionInfo() is a pointer to a DWORD value that contains the size of the buffer. This also must be set to the size of RASPPPIP before the function is called in order for it to operate properly.

For example, you could use the following to get the IP address for a newly established IP connection in the notification loop of an asynchronous RasDial() function:

case RASCS_Projected: {
   TCHAR tchRasProjectInfo[128] = TEXT("\0");
   DWORD dwReturn = 0;
   DWORD dwSize = 0;
   RASPPPIP rasPPPInfo;

   dwSize = sizeof(RASPPPIP);
   memset(&rasPPPInfo, 0, sizeof(RASPPPIP));
   rasPPPInfo.dwSize = sizeof(RASPPPIP);

   // Get the projection info. Use the global RAS handle
   // from our RasDial (g_hRasConn)
   dwReturn = RasGetProjectionInfo(&g_hRasConn, RASP_PppIp,
      (LPVOID)&rasPPPInfo, &dwSize);
   if(dwReturn != 0) {
      MessageBox(hWnd, TEXT("Couldnt get RAS IP Address"),
         TEXT("RAS Dial Error"), MB_ICONERROR|MB_OK);
      break;
   }

   wsprintf(tchRasProjectInfo, TEXT("IP Address: %s"),
      rasPPPInfo.szIpAddress);
}
break;