Function getnameinfo Wstcpippas

Syntax getnameinfo(sa: PSockAddr; salen: socklen_t; host: PChar; hostlen: DWORD; serv: PChar; servlen: DWORD; flags: Integer): Integer; stdcall;

Description

The function provides name resolution from an address to a host name.

Parameters sa: A pointer to a socket address structure containing the address and port number of the socket. For IPv4, the sa parameter points to a sockaddr_in structure; for IPv6, the sa parameter points to a sockaddr_in6 structure.

salen: The length of the structure pointed to in the sa parameter host: A pointer to the host name. The host name is returned as a fully qualified domain name (FQDN) by default.

hostlen: The length of the buffer pointed to by the host parameter. The caller must provide a buffer large enough to hold the host name, including terminating NULL characters. A value of zero indicates the caller does not want to receive the string provided in host.

serv: A pointer to the service name associated with the port number servlen: The length of the buffer pointed to by the serv parameter. The caller must provide a buffer large enough to hold the service name, including terminating NULL characters. A value of zero indicates the caller does not want to receive the string provided in serv.

flags: Used to customize processing of the getaddrinfo() function Return Value

On success, the function will return zero. Otherwise, any nonzero value will indicate failure. Use the WSAGetLastError() function to retrieve error information.

See Also getaddrinfo Example

See Listings 4-7 and 4-8 (programs EX47 and EX48).

Listing 4-8: Calling the getaddrinfo() and getnameinfo() functions program EX48;

{$APPTYPE CONSOLE}

uses SysUtils, Winsock2, WS2tcpip;

This code assumes that at the transport level, the system only supports one stream protocol (TCP) and one datagram protocol (UDP). Therefore, specifying a socket type of SOCK_STREAM is equivalent to specifying TCP and specifying a socket type of SOCK_DGRAM is equivalent to specifying UDP.

const

DEFAULT_SERVER = nil; // Will use the loopback interface

DEFAULT_FAMILY = PF_UNSPEC;// Accept either IPv4 or IPv6

DEFAULT_SOCKTYPE = SOCK_STREAM; // TCP

DEFAULT_PORT = '5001';// Arbitrary, albeit a historical test port

DEFAULT_EXTRA = 0; // Number of "extra" bytes to send

BUFFER SIZE = 65536;

type

function ReceiveAndPrint(sktConn: TSocket; var Buffer: TCharArray; BufLen: Integer): Integer; var

AmountRead: Integer; begin

AmountRead := recv(sktConn, Buffer, BufLen, 0);

if AmountRead = SOCKET_ERROR then begin

WriteLn(Format('Call to recv() failed with error %d', [WSAGetLastError])); closesocket(sktConn); WSACleanup; Halt; end;

We are not likely to see this with UDP, since there is no 'connection' established.

if AmountRead = 0 then begin

WriteLn('Server closed connection...'); closesocket(sktConn); WSACleanup; Halt; end;

WriteLn(Format('Received %d bytes from server: %s',[AmountRead, Buffer])); Result := AmountRead; end;

Buffer: TCharArray;

Server: PChar = DEFAULT_SERVER;

Family: Integer = DEFAULT_FAMILY;

SocketType : Integer = DEFAULT_S0CKTYPE;

Port: string = DEFAULT_P0RT;

i, Res, AddrLen, AmountToSend: Integer;

ExtraBytes: Integer = DEFAULT_EXTRA;

Iteration: Byte = 0;

MaxIterations: Byte = 1;

RunForever: Boolean = FALSE;

wsaData: TWSADATA;

Hints: TAddrInfo;

AddrInfo, AI: PAddrInfo;

sktConn: TSocket;

Addr: S0CKADDR_ST0RAGE;

begin if WSAStartup($0202,wsaData) <> 0 then begin

WriteLn('Call to WSAStartup() failed...'); Exit; end;

By not setting the AI_PASSIVE flag in the hints to getaddrinfo, we're indicating that we intend to use the resulting address(es) to connect to a service. This means that when the Server parameter is NULL, getaddrinfo will return one entry per allowed protocol family containing the loopback address for that family.

FillChar(Hints, SizeOf(Hints), 0); Hints.ai_family := Family; Hints.ai_socktype := SocketType;

Res := getaddrinfo(Server, PChar(Port), @Hints, Addrinfo);

WriteLn(Format('Call to getaddrinfo() failed with error %d. Unable to resolve address [%s] and port [%s]', [gai_strerror(Res), Server, Port]));

WSACleanup; Halt; end;

Try each address getaddrinfo returned, until we find one to which we can successfully connect.

while AI <> NIL do begin

Open a socket with the correct address family for this address. } sktConn := socket(AI~.ai_family, AI~.ai_socktype, AI~.ai_protocol); if sktConn = INVALID_SOCKET then begin

WriteLn(Format('Call to socket() failed with error %d',[WSAGetLastError])); ai := ai~.ai_next; inc(i); Continue; end;

Notice that nothing in this code is specific to whether we are using UDP or TCP.

When connect() is called on a datagram socket, it does not actually establish the connection as a stream (TCP) socket would. Instead, TCP/IP establishes the remote half of the (LocalIPAddress, LocalPort, RemoteIP, RemotePort) mapping. This enables us to use send() and recv() on datagram sockets, instead of recvfrom() and sendto().

if Server <> nil then

WriteLn(Format('Attempting to connect to: %s', [Server])) else

WriteLn('Attempting to connect');

if connect(sktConn, AI~.ai_addr, AI~.ai_addrlen) <> SOCKET_ERROR then

Break; i := WSAGetLastError;

if getnameinfo(AI~.ai_addr, AI~.ai_addrlen, AddrName, SizeOf(AddrName), nil, 0, NI_NUMERICHOST) <> 0 then StrPCopy(AddrName, '<unknown>'); WriteLn(Format('Call to connect() to %s failed with error %d', [AddrName, i])); closesocket(sktConn); ai := ai~.ai_next; Inc(i); end;

if AI = nil then begin

WriteLn('Fatal error: unable to connect to the server...'); WSACleanup; Halt; end;

This demonstrates how to determine to where a socket is connected.

AddrLen := sizeof(Addr);

if getpeername(sktConn, @Addr, AddrLen) = SOCKET_ERROR then begin

WriteLn(Format('Call to getpeername() failed with error %d', [WSAGetLastError])); end else begin if getnameinfo(@Addr, AddrLen, AddrName, SizeOf(AddrName), nil, 0, NI_NUMERICHOST) <> 0 then

StrPCopy(AddrName, '<unknown>'); WriteLn(Format('Connected to %s, port %u, protocol %u, protocol family %u', [AddrName, ntohs(SS_PORT(@Addr)), AI~.ai_socktype, AI~.ai_family]));

end;

{ We are done with the address info chain, so we can free it. } freeaddrinfo(AddrInfo);

Find out what local address and port the system picked for us.

AddrLen := SizeOf(Addr);

if getsockname(sktConn, @Addr, AddrLen) = SOCKET_ERROR then begin

WriteLn(Format('Call to getsockname() failed with error %d',[WSAGetLastError])); end else begin if getnameinfo(@Addr, AddrLen, AddrName, SizeOf(AddrName), NIL, 0, NI_NUMERICHOST) <> 0 then

StrPCopy(AddrName, '<unknown>'); WriteLn(Format('Using local address %s, port %d',[AddrName, ntohs(SS_PORT(@Addr))])); end;

Send and receive in a loop for the requested number of iterations.

while RunForever or (Iteration < MaxIterations) do begin

{ Compose a message to send. }

StrPCopy(Buffer, 'Message #' + IntToStr(Iteration + 1)); AmountToSend := Length('Message #' + IntToStr(Iteration + 1));

{ Send the message. Since we are using a blocking socket, this call shouldn't return until it's able to send the entire amount.

Res := send(sktConn, Buffer, AmountToSend, 0);

if Res = SOCKET_ERROR then begin

WriteLn(Format('Call to send() failed with error %d',[WSAGetLastError])); WSACleanup; Halt; end;

WriteLn(Format('Sent %d bytes (out of %d bytes) of data',[Res, AmountToSend]));

{ Clear buffer just to prove we're really receiving something. }

FillChar(Buffer, sizeof(Buffer), #0);

{ Receive and print server's reply. }

ReceiveAndPrint(sktConn, Buffer, sizeof(Buffer)); Inc(Iteration); end;// while RunForever

{ Tell system we're done sending. }

shutdown(sktConn, SD SENd); -C

Since TCP does not preserve message boundaries, there may still be more data arriving from the server. So we continue to receive data until the server closes the connection.

if SocketType = SOCK_STREAM then while ReceiveAndPrint(sktConn, Buffer, sizeof(Buffer)) <> 0 do ;

closesocket(sktConn);

finally

WSACleanup; end;

end.

Was this article helpful?

0 0

Post a comment