Starting and Closing Winsock

In this chapter, we'll build a simple application that demonstrates the two most fundamental functions in the Winsock stable, WSAStartUp() and WSACleanup(). Without exception, your application must always call WSAStartUp() before calling any other Winsock API function. If you neglect this essential step, your application will fail, sometimes in spectacular fashion. Similarly, when your application ends, it should always call WSACleanup().

At invocation, WSAStartup() performs several essential tasks, as follows:

  • Loads Winsock into memory
  • Registers the calling application
  • Allocates resources for the calling application
  • Obtains the implementation details for Winsock

You can use the implementation details returned by WSAStartup() to determine if the version of Winsock is compatible with the version requested by the calling application. Ideally, any application should run using any version of Winsock. Winsock 1.1 applications can run unchanged using Winsock 2 because Winsock 2 seamlessly maps the Winsock 1.1 functions to their equivalents in Winsock 2.

To maintain this backward compatibility, WSAStartup() performs a negotiation phase with the calling application. In this phase, the Winsock DLL and the calling application negotiate the highest version that they both can support.

If Winsock supports the version requested by the application, the call succeeds and Winsock returns the highest version that it supports. In other words, if a Winsock 1.1 application makes a request to load Winsock 1.1, and if Winsock 2 is present, the application will work with Winsock 2 because it supports all versions up to 2, including 1.1.

This negotiation phase allows Winsock and the application to support a range of Winsock versions. Table 2-1 shows the range of Winsock versions that an application can use.

Table 2-1: Different versions of Winsock

Version

Version

Highest Version Expected

Expected Version

Highest Version Supported

End Result

1.1

1.1

1.1

1.1

1.1

use 1.1

1.0, 1.1

1.0

1.1

1.0

1.0

use 1.0

1.0

1.0, 1.1

1.0

1.0

1.1

use 1.0

1.1

1.0, 1.1

1.1

1.1

1.1

use 1.1

1.1

1.0

1.1

1.0

1.0

Application fails

1.0

1.1

1.0

---

---

WSAVERNOTSUPPORTED

1.0, 1.1

1.0, 1.1

1.1

1.1

1.1

use 1.1

1.1,2.0

1.1

2.0

1.1

1.1

use 1.1

2.0

2.0

2.0

2.0

2.0

use 2.0

It is only necessary for an application to call WSAStartup() and WSACleanup() once. Sometimes, though, an application may call WSAStartup() more than once. The golden rule is to make certain that the number of calls to WSAStart-up() matches the number of calls to WSACleanup(). For example, if an application calls WSAStartup() three times, it must call WSACleanup() three times. That is, the first two calls to WSACleanup() do nothing except decrement an internal counter in Winsock; the final call to WSACleanup() for the task frees any resources.

Unlike Winsock 1.1 (which only supports one provider), the architecture of Winsock 2 supports multiple providers, which we will discuss in Chapter 4.

function WSAStartup Winsock2.pas

Syntax

WSAStartup(wVersionRequired: WORD; var IpWSAData: TWSAData): Integer; stdcall;

Description

This function initializes the Winsock DLL, registers the calling application, and allocates resources. It allows the application to specify the minimum version of Winsock it requires. The function also returns implementation information that the calling application should examine for version compatibility. After successful invocation of WSAStartup(), the application can call other Winsock functions.

Parameters wVersionRequired: The highest version that the calling application requires. The high-order byte specifies the minor version and the low-order byte the major version. Under Windows 95, the highest version that is supported is 1.1. At the time of publication, the current version is 2.2. Table 2-2 presents which version of Winsock is available for all Windows operating systems.

Table 2-2: Winsock versions for all Windows platforms

Operating System

Winsock Version

Windows 3.1

1.1

Windows 95

1.1 (2.2) See Tip

Windows 98

2.2

Windows Millennium

2.2

Windows NT 4.0

2.2

Windows XP

2.2

TIP: If you belong to that unique tribe of developers that still uses Win95 as a development platform, and you want to develop Winsock 2 applications for Windows 95, you will have to upgrade Winsock 1.1. The upgrade is available from the Microsoft web site (www.microsoft.com).

wsData: This is a placeholder for the WSAData record that contains implementation details for Winsock. When we call WSAStartUp(), the function populates the WSAData record, which is defined in Winsock2.pas as follows:

WSAData = record wVersion: WORD; wHighVersion: WORD;

szDescription: array [0..WSADESCRIPTI0N_LEN] of Char;

szSystemStatus: array [0..WSASYS_STATUS_LEn] of Char;

iMaxSockets: Word;

iMaxUdpDg: Word;

lpVendorlnfo: PChar;

end;

LPWSADATA = ^WSAData; TWsaData = WSAData; PWsaData = LPWSADATA;

Table 2-3 describes these fields of the WSAData data structure.

Table 2-3: Values for the main members of the WSAData structure

Member

Meaning

wVersion

The version of the Windows Sockets specification that the Windows Sockets DLL expects the calling application to use

wHighVersion

The highest version of the Windows Sockets specification that this DLL can support (also encoded as above). Normally this will be the same as wVersion.

szDescription

A NULL-terminated ASCII string into which the Windows Sockets DLL copies a description of the Windows Sockets implementation. The text may be up to 256 characters in length and contain any characters except control and formatting characters. The information in this field is often used by an application to provide a status message.

szSystemStatus

A NULL-terminated ASCII string into which the Windows Sockets DLL copies relevant status or configuration information. The Windows Sockets DLL should use this field only if the information might be useful to the user or support staff; it should not be considered as an extension of the szDescription field.

iMaxSockets

This field is retained for backward compatibility but should be ignored for version 2 and later, as no single value can be appropriate for all underlying service providers.

iMaxUdpDg

This value should be ignored for version 2 and onward. It is retained for backward compatibility with Windows Sockets specification 1.1 but should not be used when developing new applications. For the actual maximum message size specific to a particular Windows Sockets service provider and socket type, applications should use getsockopt() to retrieve the value of option SO MAX MSG SIZE after a socket has been created.

lpVendorInfo

This value should be ignored for version 2 and onward. It is retained for backward compatibility with Windows Sockets specification 1.1. Applications needing to access vendor-specific configuration information should use getsockopt() to retrieve the value of option PVD CONFIG. The definition of this value (if utilized) is beyond the scope of this specification.

Return Value

If successful, WSAStartup() will return zero. As we'll see when we cover other Winsock functions, WSAStartup() is the exception to the rule in that it does not return a Winsock error that we can use to determine the cause of that error. Since WSAStartup() is a function that initializes the Winsock DLL, which includes the WSAGetLastError() function to report Winsock-specific errors, it cannot call WSAGetLastError() because the DLL is not loaded. It is a conundrum like the proverbial chicken and egg problem. Therefore, to test for the success or failure to initialize Winsock, we just check for the return value of zero. Listing 2-1 demonstrates how to check the return value from WSAStartup().

Returning to the WSAData data structure, as far as programming Winsock applications goes, the most important fields that you should always read or check are wVersion and wHighVersion.

The WSAData structure in Winsock 2 no longer necessarily applies to a single vendor's stack. This means that Winsock 2 applications should ignore iMaxSockets, iMaxUdpDg, and lpVendorInfo, as these are irrelevant. However, you can retrieve provider-specific information by calling the getsockopt() function. We'll discuss this function briefly in Chapter 6, "Socket Options."

See Also getsockopt, send, sendto, WSACleanup Example

Listing 2-1 (program EX21 on the companion CD) shows how to load Winsock using WSAStartup() and how to verify version compatibility. It also shows how to close a Winsock application properly using WSACleanup().

function WSACleanup Winsock2.pas

Syntax

WSACleanup: Integer; stdcall; Description

This function unloads the Winsock DLL. A call to WSACleanup() will cancel the following operations: blocking and asynchronous calls, overlapped send and receive operations, and close and free any open sockets. Please note that any data pending may be lost.

Parameters

None

Return Value

If successful, the function will return a value of zero. Otherwise, the function returns a value of SOCKET_ERROR. To retrieve information about the error, call the WSAGetLastError() function. Possible error codes are WSANOT-INITIALISED, WSAENETDOWN, and WSAEINPROGRESS. See Appendix B for a detailed description of the error codes.

See Also closesocket, shutdown, WSAStartup Example

Listing 2-1 shows how to load and unload the Winsock DLL by calling WSAStartup() and WSACleanup(), respectively.

Listing 2-1: Loading and unloading Winsock

Example EX21 demonstrates how to load and unload Winsock correctly. It also demonstrates how to call different versions of Winsock. In this example, the program expects an input of 1 for Winsock 1.1 or 2 for Winsock 2.2. Failing that, the program displays a warning and halts. To run this program from the IDE, Select Run|Parameters from the Run option in the IDE toolbar and enter 1 or 2 in the Parameters edit box. To run the application from the command line, type in the following:

ex21 1 or ex21 2

for WinSock 1.1 or Winsock 2.2, respectively.

program EX21;

{$APPTYPE CONSOLE}

uses WinSock2, SysUtils;

const

Version1 : Word = $101; // Version 1.1 Version2 : word = $202; // Version 2.2

WSAData : TWSAData; Version : Word; begin Version := 0; if ParamStr(1) = '1' then Version := Version1 else if ParamStr(1) = '2' then Version := Version2 else begin

WriteLn('Missing version. Please input 1 for Version 1.1 or 2 for Version 2.2'); Halt; end;

if WSAStartUp(Word(Version), WSAData) = 0 then // yes, Winsock does exist ... try

WriteLn(Format('Version = %d.%d',[Hi(WSAData.wVersion),Lo(WSAData.wVersion)])); WriteLn(Format('High Version = %d.%d',[Hi(WSAData.wHighVersion),

Lo(WSAData.wHighVersion)])); WriteLn(Format('Description = %s',[WSAData.szDescription])); WriteLn(Format('System Status = %s',[WSAData.szSystemStatus])); WriteLn(Format('Maximum Number of Sockets = %d',[WSAData.iMaxSockets])); WriteLn(Format('Maximum Size of a Datagram = %d bytes',[WSAData.iMaxUdpDg])); if WSAData.lpVendorInfo <> NIL then WriteLn(Format('Vendor Information = %s',[WSAData.lpVendorInfo])); finally WSACleanUp; end else WriteLn('Failed to initialize Winsock.'); end.

Figure 2-1 shows output from EX21 calling Winsock 1.1. Compare this output to that produced by the same program but calling 2.2 in Figure 2-2.

¡^E:\Dev\Tomes\Final\Chapter OZ - Winsock Fundamentals\EX2i

Uersion =1.1

High Uersion = 2.2

Description = UinSoek 2.0

System Status » Running

Maximum Number of Sockets = 32767

Maximum Size of a Datagram = 65467 bytes

Figure 2-

Notice that the fields iMaxSockets and iMaxUdpDg, used to return the maximum number of sockets and the maximum size of the message, respectively, give us no useful information.

FVE;\Pev\Tpmes\Finar\Cbapter 02 - Winsock Fundamentals\EX2i

High Uersion =2.2

Description = WinSock 2,0

System Status a Running

Maximum Number- of Sockets = 0

Maximum Size of a Datagram - 0 bytes

Figure 2-2

Was this article helpful?

0 0

Post a comment