I/O Control Operations (Winsock)
This section describes the I/O control (IOCTL) operations supported by Winsock. These operations allow applications to control the behavior of network sockets beyond the standard read and write operations.
Overview
Winsock supports a variety of IOCTLs that can be performed using the ioctlsocket
function. These controls range from retrieving network interface information to setting socket options that are not exposed through standard setsockopt
calls.
Common IOCTL Codes
The following are some of the commonly used IOCTL codes for Winsock:
SIO_GET_EXTENSION_FUNCTION_POINTER
: Retrieves a pointer to a Winsock extension function.SIO_GET_BROADCAST_ERROR
: Retrieves information about a broadcast error.SIO_ADDRESS_LIST_FROM_NAME
: Retrieves a list of network addresses for a given name.SIO_ADDRESS_LIST_QUERY
: Retrieves a list of network addresses for the local host.SIO_GET_REMOTE_ADDRESS
: Retrieves the remote address of a connected socket.SIO_GET_LOCAL_ADDRESS
: Retrieves the local address of a socket.SIO_KEEPALIVE_VALS
: Sets or retrieves Keep-Alive parameter values.SIO_RCVALL
: Enables or disables raw socket receive mode. (Deprecated)SIO_UDP_CONNRESET
: Enables or disables the UDP connection reset behavior.SIO_SET_LINK
: Sets the link interface for a socket. (Specific to certain providers)
Using ioctlsocket
The ioctlsocket
function is used to perform these operations. Its signature is as follows:
s
: A descriptor identifying a socket.cmd
: The IOCTL code to perform.argp
: A pointer to the buffer that contains any data required for the operation, or where the results of the operation will be stored. The type and meaning of this argument depend on the specific IOCTL code.
Example: Retrieving Remote Address
The following C++ snippet demonstrates how to use ioctlsocket
to get the remote address of a connected socket:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#pragma comment(lib, "Ws2_32.lib")
int main() {
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
std::cerr << "WSAStartup failed." << std::endl;
return 1;
}
SOCKET clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket == INVALID_SOCKET) {
std::cerr << "socket creation failed: " << WSAGetLastError() << std::endl;
WSACleanup();
return 1;
}
// Assume clientSocket is connected to a server at this point...
// For demonstration purposes, we'll just show the ioctl call.
sockaddr_in remoteAddr;
int addrLen = sizeof(remoteAddr);
u_long argp = (u_long)&remoteAddr; // Cast to u_long* as required by ioctlsocket
if (ioctlsocket(clientSocket, SIO_GET_REMOTE_ADDRESS, &argp) != SOCKET_ERROR) {
// Successfully retrieved remote address
char ipStr[INET_ADDRSTRLEN];
InetNtop(AF_INET, &remoteAddr.sin_addr, ipStr, INET_ADDRSTRLEN);
std::cout << "Remote IP: " << ipStr << std::endl;
std::cout << "Remote Port: " << ntohs(remoteAddr.sin_port) << std::endl;
} else {
std::cerr << "SIO_GET_REMOTE_ADDRESS failed: " << WSAGetLastError() << std::endl;
}
closesocket(clientSocket);
WSACleanup();
return 0;
}
ioctlsocket
(u_long*
) is a legacy type. In modern C++, you might need to cast your pointer accordingly. The actual data buffer type depends on the IOCTL. For SIO_GET_REMOTE_ADDRESS
, it's a pointer to a sockaddr_in
structure.