Address Structures

Note: This documentation describes features available in Windows operating systems. Information about feature availability may be updated as new versions of the operating system are released. For the latest information, refer to the official Microsoft documentation.

Introduction to Address Structures

Network programming relies heavily on the ability to represent and manage network addresses. In the Windows Sockets API (Winsock), various structures are defined to hold information about socket addresses. These structures are crucial for functions like bind, connect, sendto, and recvfrom.

The specific structure used often depends on the address family (e.g., IPv4 or IPv6).

Common Address Structures

The primary structure for general socket addressing is SOCKADDR, but in practice, you'll often use more specific structures that are cast to SOCKADDR or SOCKADDR_STORAGE.

SOCKADDR Structure

This is a generic structure that can hold any socket address. It is typically used as a generic pointer, with the actual type determined by the sa_family member.

typedef struct sockaddr {
    u_short sa_family;       // Address family (AF_INET, AF_INET6, AF_UNSPEC, etc.)
    char    sa_data[14];     // Protocol-specific address information
} SOCKADDR, *PSOCKADDR, FAR *LPSOCKADDR;

The sa_data field is a generic buffer. For specific address families, specialized structures are used and then cast to SOCKADDR.

SOCKADDR_IN Structure (IPv4)

This structure represents an IPv4 socket address. It includes the address family, port number, and IP address.

typedef struct sockaddr_in {
    short          sin_family;        // Address family (AF_INET)
    unsigned short sin_port;          // Port number
    struct in_addr sin_addr;          // IPv4 address
    char           sin_zero[8];       // Not used
} SOCKADDR_IN;
  • sin_family: Must be set to AF_INET for IPv4.
  • sin_port: The port number, in network byte order.
  • sin_addr: An in_addr structure containing the IPv4 address.

SOCKADDR_IN6 Structure (IPv6)

This structure represents an IPv6 socket address. It is more complex than SOCKADDR_IN due to the larger IPv6 address space and additional features.

typedef struct sockaddr_in6 {
    short          sin6_family;       // Address family (AF_INET6)
    USHORT         sin6_port;         // Port number
    ULONG          sin6_flowinfo;     // IPv6 flow information
    struct in6_addr sin6_addr;         // IPv6 address
    ULONG          sin6_scope_id;     // Scope ID
} SOCKADDR_IN6;
  • sin6_family: Must be set to AF_INET6 for IPv6.
  • sin6_port: The port number, in network byte order.
  • sin6_addr: An in6_addr structure containing the 16-byte IPv6 address.
  • sin6_flowinfo: Flow information for the IPv6 packet.
  • sin6_scope_id: Scope identifier, relevant for link-local addresses.

SOCKADDR_STORAGE Structure

This structure is designed to be large enough to hold any sockaddr structure, including both IPv4 and IPv6 addresses. It's useful when you need to store an address without knowing its family beforehand.

typedef struct sockaddr_storage {
    short  ss_family;        // Address family
    char   __ss_padding[6];  // Padding to align the structure
    // The actual address data follows, which will be either SOCKADDR_IN,
    // SOCKADDR_IN6, or another protocol-specific address structure.
    union {
        char   __ss_data[128];
        sockaddr_in     __ss_ign_sockaddr_in;  // For IPv4
        sockaddr_in6    __ss_ign_sockaddr_in6; // For IPv6
    };
} SOCKADDR_STORAGE, *PSOCKADDR_STORAGE, *LPSOCKADDR_STORAGE;

When using SOCKADDR_STORAGE, you must check the ss_family member to determine which type of address structure is actually contained within it.

Address Families

The sa_family (or sin_family/ss_family) member of these structures specifies the address family.

  • AF_UNSPEC: The address family is unknown or unsupported.
  • AF_INET: The Internet address family (IPv4).
  • AF_INET6: The Internet address family (IPv6).
  • AF_NETBIOS: NetBIOS (less common now).
  • AF_IRDA: Infrared Data Association.

The most common families for modern networking are AF_INET and AF_INET6.

Working with Addresses

You will often use helper functions to convert between string representations of addresses (like "192.168.1.1" or "::1") and their binary forms within the address structures.

  • inet_pton (and inet_ptr for IPv6): Converts a string to a network address structure.
  • inet_ntop (and inet_ntri for IPv6): Converts a network address structure to a string.
  • getaddrinfo and freeaddrinfo: A more modern and flexible way to resolve hostnames and service names into a linked list of socket address structures.

Example using inet_pton and SOCKADDR_IN:

#include <winsock2.h>
#include <ws2ipdef.h> // For IN_ADDR structure

// ... initialization of Winsock ...

SOCKADDR_IN ipv4_addr;
const char* ip_string = "192.168.1.100";
int port = 8080;

memset(&ipv4_addr, 0, sizeof(ipv4_addr));
ipv4_addr.sin_family = AF_INET;
ipv4_addr.sin_port = htons(port); // Convert port to network byte order

if (inet_pton(AF_INET, ip_string, &ipv4_addr.sin_addr) <= 0) {
    // Error handling: Invalid IP address string
    printf("inet_pton failed.\n");
} else {
    // Successfully populated the address structure
    printf("Address structure populated for %s:%d\n", ip_string, port);
}