SIO_ACQUIRE_PORT_RESERVATION código de control
Descripción
El código de control SIO_ACQUIRE_PORT_RESERVATION adquiere una reserva en tiempo de ejecución para un bloque de puertos TCP o UDP.
Para realizar esta operación, llame a la función WSAIoctl o WSPIoctl con los parámetros siguientes.
int WSAIoctl(
(socket) s, // descriptor identifying a socket
SIO_ACQUIRE_PORT_RESERVATION, // dwIoControlCode
(LPVOID) lpvInBuffer, // pointer to an INET_PORT_RANGE structure
(DWORD) cbInBuffer, // size, in bytes, of the input buffer
(LPVOID) lpvOutBuffer, // pointer to an INET_PORT_RESERVATION_INSTANCE structure
(DWORD) cbOutBuffer, // size, in bytes, of the output buffer
(LPDWORD) lpcbBytesReturned, // number of bytes returned
(LPWSAOVERLAPPED) lpOverlapped, // OVERLAPPED structure
(LPWSAOVERLAPPED_COMPLETION_ROUTINE) lpCompletionRoutine, // completion routine
);
int WSPIoctl(
(socket) s, // descriptor identifying a socket
SIO_ACQUIRE_PORT_RESERVATION, // dwIoControlCode
(LPVOID) lpvInBuffer, // pointer to an INET_PORT_RANGE structure
(DWORD) cbInBuffer, // size, in bytes, of the input buffer
(LPVOID) lpvOutBuffer, // pointer to a INET_PORT_RESERVATION_INSTANCE structure
(DWORD) cbOutBuffer, // size, in bytes, of the output buffer
(LPDWORD) lpcbBytesReturned, // number of bytes returned
(LPWSAOVERLAPPED) lpOverlapped, // OVERLAPPED structure
(LPWSAOVERLAPPED_COMPLETION_ROUTINE) lpCompletionRoutine, // completion routine
(LPWSATHREADID) lpThreadId, // a WSATHREADID structure
(LPINT) lpErrno // a pointer to the error code.
);
Parámetros
s
Descriptor que identifica un socket.
dwIoControlCode
Código de control para la operación. Use SIO_ACQUIRE_PORT_RESERVATION para esta operación.
lpvInBuffer
Puntero al búfer de entrada. Este parámetro contiene un puntero a una estructura de INET_PORT_RANGE que especifica el número de punto inicial y el número de puertos que se van a reservar.
cbInBuffer
Tamaño, en bytes, del búfer de entrada. Este parámetro debe ser el tamaño de la estructura INET_PORT_RANGE .
lpvOutBuffer
Puntero al búfer de salida. Si la salida es correcta, este parámetro contiene un puntero a una estructura INET_PORT_RESERVATION_INSTANCE .
cbOutBuffer
Tamaño, en bytes, del búfer de salida. Este parámetro debe ser al menos el tamaño de la estructura INET_PORT_RESERVATION_INSTANCE .
lpcbBytesReturned
Puntero a una variable que recibe el tamaño, en bytes, de los datos almacenados en el búfer de salida.
Si el búfer de salida es demasiado pequeño, se produce un error en la llamada, WSAGetLastError devuelve WSAEINVAL y el parámetro lpcbBytesReturned apunta a un valor DWORD de cero.
Si lpOverlapped es NULL, el valor DWORD al que apunta el parámetro lpcbBytesReturned que se devuelve en una llamada correcta no puede ser cero.
Si el parámetro lpOverlapped no es NULL para sockets superpuestos, las operaciones que no se pueden completar inmediatamente se iniciarán y la finalización se indicará más adelante. El valor DWORD al que apunta el parámetro lpcbBytesReturned devuelto puede ser cero, ya que el tamaño de los datos almacenados no se puede determinar hasta que se haya completado la operación superpuesta. El estado de finalización final se puede recuperar cuando se señala el método de finalización adecuado cuando se ha completado la operación.
lpvOverlapped
Puntero a una estructura WSAOVERLAPPED .
Si el socket se creó sin el atributo superpuesto, se omite el parámetro lpOverlapped .
Si se abrió con el atributo superpuesto y el parámetro lpOverlapped no es NULL, la operación se realiza como una operación superpuesta (asincrónica). En este caso, el parámetro lpOverlapped debe apuntar a una estructura WSAOVERLAPPED válida.
En el caso de las operaciones superpuestas, la función WSAIoctl o WSPIoctl devuelve inmediatamente y el método de finalización adecuado se señala cuando se ha completado la operación. De lo contrario, la función no devuelve hasta que se haya completado la operación o se produzca un error.
lpCompletionRoutine
Tipo: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE
Puntero a la rutina de finalización a la que se llama cuando se ha completado la operación (se omite para sockets no superpuestos).
lpThreadId
Puntero a una estructura WSATHREADID que va a usar el proveedor en una llamada posterior a WPUQueueApc. El proveedor debe almacenar la estructura WSATHREADID a la que se hace referencia (no el puntero a la misma) hasta que se devuelva la función WPUQueueApc .
Nota Este parámetro solo se aplica a la función WSPIoctl .
lpErrno
Puntero al código de error.
Nota Este parámetro solo se aplica a la función WSPIoctl .
Valor devuelto
Si la operación se completa correctamente, la función WSAIoctl o WSPIoctl devuelve cero.
Si se produce un error en la operación o está pendiente, la función WSAIoctl o WSPIoctl devuelve SOCKET_ERROR. Para obtener información de error extendida, llame a WSAGetLastError.
Código de error | Significado |
---|---|
WSA_IO_PENDING | La operación de E/S superpuesta está en curso. Este valor se devuelve si se inició correctamente una operación superpuesta y la finalización se indicará en un momento posterior. |
WSA_OPERATION_ABORTED | Se ha anulado la operación de E/S debido a una solicitud de la aplicación o una salida del subproceso. Este error se devuelve si se canceló una operación superpuesta debido al cierre del socket o a la ejecución del comando SIO_FLUSH IOCTL. |
WSAEFAULT | El sistema detectó una dirección de puntero no válida al intentar usar un argumento de puntero en una llamada. Este error se devuelve del parámetro lpvInBuffer, lpvoutBuffer, lpcbBytesReturned, lpOverlapped o lpCompletionRoutine no está totalmente incluido en una parte válida del espacio de direcciones del usuario. |
WSAEINPROGRESS | Se está ejecutando una operación de bloqueo actualmente. Este error se devuelve si se invoca la función cuando hay una devolución de llamada en curso. |
WSAEINTR | Una operación de bloqueo se interrumpió mediante una llamada a WSACancelBlockingCall. Este error se devuelve si se interrumpió una operación de bloqueo. |
WSAEINVAL | Se proporcionó un argumento no válido. Este error se devuelve si el parámetro dwIoControlCode no es un comando válido o si un parámetro de entrada especificado no es aceptable o el comando no es aplicable al tipo de socket especificado. |
WSAENETDOWN | Una operación de socket encontró una red inactiva. Este error se devuelve si se ha producido un error en el subsistema de red. |
WSAENOTSOCK | Se intentó realizar una operación en algo que no es un socket. Este error se devuelve si el descriptor s no es un socket. |
WSAEOPNOTSUPP | La operación intentada no se admite para el tipo de objeto al que se hace referencia. Este error se devuelve si no se admite el comando IOCTL especificado. Este error también se devuelve si el proveedor de transporte no admite el SIO_ACQUIRE_PORT_RESERVATION IOCTL. Este error también se devuelve cuando se intenta usar el SIO_ACQUIRE_PORT_RESERVATION IOCTL en un socket distinto de UDP o TCP. |
Observaciones
El SIO_ACQUIRE_PORT_RESERVATION IOCTL es compatible con Windows Vista y versiones posteriores del sistema operativo.
Las aplicaciones y los servicios que necesitan reservar puertos se dividen en dos categorías. La primera categoría incluye componentes que necesitan un puerto determinado como parte de su operación. Por lo general, estos componentes prefieren especificar su puerto necesario en el momento de la instalación (por ejemplo, en un manifiesto de aplicación). La segunda categoría incluye componentes que necesitan cualquier puerto o bloque de puertos disponibles en tiempo de ejecución. Estas dos categorías corresponden a solicitudes de reserva de puertos comodín y específicas. Las solicitudes de reserva específicas pueden ser persistentes o en tiempo de ejecución, mientras que las solicitudes de reserva de puerto comodín solo se admiten en tiempo de ejecución.
El SIO_ACQUIRE_PORT_RESERVATION IOCTL se usa para solicitar una reserva en tiempo de ejecución para un bloque de puertos TCP o UDP. Para las reservas de puertos en tiempo de ejecución, el grupo de puertos requiere que las reservas se consuman desde el proceso en cuyo socket se concedió la reserva. Las reservas de puertos en tiempo de ejecución solo duran mientras dure el socket en el que se llamó al SIO_ACQUIRE_PORT_RESERVATION IOCTL. En cambio, las reservas de puertos persistentes creadas mediante la función CreatePersistentTcpPortReservation o CreatePersistentUdpPortReservation pueden consumirse por cualquier proceso con la capacidad de obtener reservas persistentes.
Una vez obtenida una reserva de puertos TCP o UDP en tiempo de ejecución, una aplicación puede solicitar asignaciones de puerto desde la reserva de puertos abriendo un socket TCP o UDP y, a continuación, llamando a la función WSAIoctl especificando el SIO_ASSOCIATE_PORT_RESERVATION IOCTL y pasando el token de reserva antes de emitir una llamada a la función bind en el socket.
Si los parámetros lpOverlapped y lpCompletionRoutine son NULL, el socket de esta función se tratará como un socket no superpuesto. En el caso de un socket no superpuesto, se omiten los parámetros lpOverlapped y lpCompletionRoutine , salvo que la función puede bloquearse si el socket s está en modo de bloqueo. Si el socket s está en modo de no bloqueo, esta función se bloqueará, ya que este IOCTL determinado no admite el modo de no bloqueo.
En el caso de sockets superpuestos, las operaciones que no se pueden completar inmediatamente se iniciarán y la finalización se indicará más adelante.
Cualquier IOCTL puede bloquearse indefinidamente, dependiendo de la implementación del proveedor de servicios. Si la aplicación no puede tolerar el bloqueo en una llamada de función WSAIoctl o WSPIoctl , se recomienda que las E/S superpuestas se bloqueen en las E/S superpuestas.
El SIO_ACQUIRE_PORT_RESERVATION IOCTL puede producir un error con WSAEINTR o WSA_OPERATION_ABORTED en los casos siguientes:
- El Administrador de E/S cancela la solicitud.
- El socket está cerrado.
Ejemplos
En el ejemplo siguiente se adquiere una reserva de puertos en tiempo de ejecución y, a continuación, se crea un socket y se asigna un puerto de la reserva de puertos en tiempo de ejecución para el socket y, a continuación, se cierra el socket y se libera la reserva de puertos en tiempo de ejecución.
#ifndef UNICODE
#define UNICODE
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h.>
#include <winsock2.h>
#include <mstcpip.h>
#include <ws2ipdef.h>
#include <stdio.h>
#include <stdlib.h>
// Need to link with Ws2_32.lib for Winsock functions
#pragma comment(lib, "ws2_32.lib")
int wmain(int argc, WCHAR ** argv)
{
// Declare and initialize variables
int startPort = 0; // host byte order
int numPorts = 0;
USHORT startPortns = 0; // Network byte order
INET_PORT_RANGE portRange = { 0 };
INET_PORT_RESERVATION_INSTANCE portRes = { 0 };
unsigned long status = 0;
WSADATA wsaData = { 0 };
int iResult = 0;
SOCKET sock = INVALID_SOCKET;
int iFamily = AF_INET;
int iType = 0;
int iProtocol = 0;
SOCKET sockRes = INVALID_SOCKET;
DWORD bytesReturned = 0;
// Note that the sockaddr_in struct works only with AF_INET not AF_INET6
// An application needs to use the sockaddr_in6 for AF_INET6
sockaddr_in service;
sockaddr_in sockName;
int nameLen = sizeof (sockName);
// Validate the parameters
if (argc != 6) {
wprintf
(L"usage: %s <addressfamily> <type> <protocol> <StartingPort> <NumberOfPorts>\n",
argv[0]);
wprintf(L"Opens a socket for the specified family, type, & protocol\n");
wprintf
(L"and then acquires a runtime port reservation for the protocol specified\n");
wprintf(L"%ws example usage\n", argv[0]);
wprintf(L" %ws 2 2 17 5000 20\n", argv[0]);
wprintf(L" where AF_INET=2 SOCK_DGRAM=2 IPPROTO_UDP=17 StartPort=5000 NumPorts=20", argv[0]);
return 1;
}
iFamily = _wtoi(argv[1]);
iType = _wtoi(argv[2]);
iProtocol = _wtoi(argv[3]);
startPort = _wtoi(argv[4]);
if (startPort < 0 || startPort > 65535) {
wprintf(L"Starting point must be either 0 or between 1 and 65,535\n");
return 1;
}
startPortns = htons((USHORT) startPort);
numPorts = _wtoi(argv[5]);
if (numPorts < 0) {
wprintf(L"Number of ports must be a positive number\n");
return 1;
}
portRange.StartPort = startPortns;
portRange.NumberOfPorts = (USHORT) numPorts;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
wprintf(L"WSAStartup failed with error = %d\n", iResult);
return 1;
}
sock = socket(iFamily, iType, iProtocol);
if (sock == INVALID_SOCKET) {
wprintf(L"socket function failed with error = %d\n", WSAGetLastError());
WSACleanup();
return 1;
} else {
wprintf(L"socket function succeeded\n");
iResult =
WSAIoctl(sock, SIO_ACQUIRE_PORT_RESERVATION, (LPVOID) & portRange,
sizeof (INET_PORT_RANGE), (LPVOID) & portRes,
sizeof (INET_PORT_RESERVATION_INSTANCE), &bytesReturned, NULL, NULL);
if (iResult != 0) {
wprintf(L"WSAIoctl(SIO_ACQUIRE_PORT_RESERVATION) failed with error = %d\n",
WSAGetLastError());
closesocket(sock);
WSACleanup();
return 1;
} else {
wprintf
(L"WSAIoctl(SIO_ACQUIRE_PORT_RESERVATION) succeeded, bytesReturned = %u\n",
bytesReturned);
wprintf(L" Starting port=%d, Number of Ports=%d, Token=%I64d\n",
htons(portRes.Reservation.StartPort),
portRes.Reservation.NumberOfPorts, portRes.Token);
sockRes = socket(iFamily, iType, iProtocol);
if (sockRes == INVALID_SOCKET) {
wprintf(L"socket function for second socket failed with error = %d\n",
WSAGetLastError());
closesocket(sock);
WSACleanup();
return 1;
} else {
wprintf(L"socket function for second socket succeeded\n");
iResult =
WSAIoctl(sock, SIO_ASSOCIATE_PORT_RESERVATION,
(LPVOID) & portRes.Token, sizeof (ULONG64), NULL, 0,
&bytesReturned, NULL, NULL);
if (iResult != 0) {
wprintf
(L"WSAIoctl(SIO_ASSOCIATE_PORT_RESERVATION) failed with error = %d\n",
WSAGetLastError());
} else {
wprintf
(L"WSAIoctl(SIO_ASSOCIATE_PORT_RESERVATION) succeeded, bytesReturned = %u\n",
bytesReturned);
service.sin_family = (ADDRESS_FAMILY) iFamily;
service.sin_addr.s_addr = INADDR_ANY;
service.sin_port = 0;
iResult = bind(sock, (SOCKADDR *) & service, sizeof (service));
if (iResult == SOCKET_ERROR)
wprintf(L"bind failed with error = %d\n", WSAGetLastError());
else {
wprintf(L"bind succeeded\n");
iResult = getsockname(sock, (SOCKADDR *) & sockName, &nameLen);
if (iResult == SOCKET_ERROR)
wprintf(L"getsockname failed with error = %d\n",
WSAGetLastError());
else {
wprintf(L"getsockname succeeded\n");
wprintf(L"Port number allocated = %u\n",
ntohs(sockName.sin_port));
}
}
}
}
// comment out this block of code if you don't want to delete the reservation just created
iResult =
WSAIoctl(sock, SIO_RELEASE_PORT_RESERVATION, (LPVOID) & portRes.Token,
sizeof (ULONG64), NULL, 0, &bytesReturned, NULL, NULL);
if (iResult != 0) {
wprintf
(L"WSAIoctl(SIO_RELEASE_PORT_RESERVATION) failed with error = %d\n",
WSAGetLastError());
} else {
wprintf
(L"WSAIoctl(SIO_RELEASE_PORT_RESERVATION) succeeded, bytesReturned = %u\n",
bytesReturned);
}
}
if (sockRes != INVALID_SOCKET) {
iResult = closesocket(sockRes);
if (iResult == SOCKET_ERROR) {
wprintf(L"closesocket for second socket failed with error = %d\n",
WSAGetLastError());
}
}
if (sock != INVALID_SOCKET) {
iResult = closesocket(sock);
if (iResult == SOCKET_ERROR) {
wprintf(L"closesocket for first socket failed with error = %d\n",
WSAGetLastError());
}
}
}
WSACleanup();
return 0;
}
Vea también
CreatePersistentTcpPortReservation
CreatePersistentUdpPortReservation
DeletePersistentTcpPortReservation
DeletePersistentUdpPortReservation
INET_PORT_RESERVATION_INSTANCE
LookupPersistentTcpPortReservation
LookupPersistentUdpPortReservation