codice di controllo SIO_ACQUIRE_PORT_RESERVATION
Descrizione
Il codice di controllo SIO_ACQUIRE_PORT_RESERVATION acquisisce una prenotazione di runtime per un blocco di porte TCP o UDP.
Per eseguire questa operazione, chiamare la funzione WSAIoctl o WSPIoctl con i parametri seguenti.
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.
);
Parametri
s
Descrittore che identifica un socket.
dwIoControlCode
Codice di controllo per l'operazione. Usare SIO_ACQUIRE_PORT_RESERVATION per questa operazione.
lpvInBuffer
Puntatore al buffer di input. Questo parametro contiene un puntatore a una struttura INET_PORT_RANGE che specifica il numero di punto iniziale e il numero di porte da riservare.
cbInBuffer
Dimensioni, in byte, del buffer di input. Questo parametro deve essere la dimensione della struttura INET_PORT_RANGE .
lpvOutBuffer
Puntatore al buffer di output. Nell'output riuscito, questo parametro contiene un puntatore a una struttura INET_PORT_RESERVATION_INSTANCE .
cbOutBuffer
Dimensioni, in byte, del buffer di output. Questo parametro deve essere almeno la dimensione della struttura INET_PORT_RESERVATION_INSTANCE .
lpcbBytesReturned
Puntatore a una variabile che riceve le dimensioni, in byte, dei dati archiviati nel buffer di output.
Se il buffer di output è troppo piccolo, la chiamata ha esito negativo, WSAGetLastError restituisce WSAEINVAL e il parametro lpcbBytesReturned punta a un valore DWORD pari a zero.
Se lpOverlapped è NULL, il valore DWORD puntato al parametro lpcbBytesReturned restituito in una chiamata riuscita non può essere zero.
Se il parametro lpOverlapped non è NULL per i socket sovrapposti, le operazioni che non possono essere completate immediatamente verranno avviate e il completamento verrà indicato in un secondo momento. Il valore DWORD indicato dal parametro lpcbBytesReturned restituito può essere zero poiché le dimensioni dei dati archiviati non possono essere determinate fino al completamento dell'operazione sovrapposta. Lo stato di completamento finale può essere recuperato quando il metodo di completamento appropriato viene segnalato al termine dell'operazione.
lpvOverlapped
Puntatore a una struttura WSAOVERLAPPED .
Se il socket s è stato creato senza l'attributo sovrapposto, il parametro lpOverlapped viene ignorato .
Se s è stato aperto con l'attributo sovrapposto e il parametro lpOverlapped non è NULL, l'operazione viene eseguita come operazione sovrapposta (asincrona). In questo caso, il parametro lpOverlapped deve puntare a una struttura WSAOVERLAPPED valida.
Per le operazioni sovrapposte, la funzione WSAIoctl o WSPIoctl restituisce immediatamente e il metodo di completamento appropriato viene segnalato al termine dell'operazione. In caso contrario, la funzione non restituisce finché l'operazione non è stata completata o si verifica un errore.
lpCompletionRoutine
Tipo: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE
Puntatore alla routine di completamento chiamata quando l'operazione è stata completata (ignorata per socket non sovrapposti).
lpThreadId
Puntatore a una struttura WSATHREADID da usare dal provider in una chiamata successiva a WPUQueueApc. Il provider deve archiviare la struttura WSATHREADID a cui fa riferimento (non lo stesso puntatore) fino a quando la funzione WPUQueueApc restituisce.
Nota Questo parametro si applica solo alla funzione WSPIoctl .
lpErrno
Puntatore al codice di errore.
Nota Questo parametro si applica solo alla funzione WSPIoctl .
Valore restituito
Se l'operazione viene completata correttamente, la funzione WSAIoctl o WSPIoctl restituisce zero.
Se l'operazione ha esito negativo o è in sospeso, la funzione WSAIoctl o WSPIoctl restituisce SOCKET_ERROR. Per ottenere informazioni sull'errore estese, chiamare WSAGetLastError.
Codice di errore | Significato |
---|---|
WSA_IO_PENDING | L'operazione di I/O sovrapposta è in corso. Questo valore viene restituito se un'operazione sovrapposta è stata avviata correttamente e il completamento verrà indicato in un secondo momento. |
WSA_OPERATION_ABORTED | Operazione di I/O annullata per uscita da un thread o su richiesta di un'applicazione. Questo errore viene restituito se un'operazione sovrapposta è stata annullata a causa della chiusura del socket o dell'esecuzione del comando IOCTL SIO_FLUSH. |
WSAEFAULT | Il sistema ha rilevato un indirizzo puntatore non valido nel tentativo di usare un argomento puntatore in una chiamata. Questo errore viene restituito del parametro lpvInBuffer, lpvoutBuffer, lpcbBytesReturned, lpOverlapped o lpCompletionRoutine non è totalmente contenuto in una parte valida dello spazio indirizzi utente. |
WSAEINPROGRESS | È in corso un'operazione di blocco. Questo errore viene restituito se la funzione viene richiamata quando è in corso un callback. |
WSAEINTR | Un'operazione di blocco è stata interrotta da una chiamata a WSACancelBlockingCall. Questo errore viene restituito se un'operazione di blocco è stata interrotta. |
WSAEINVAL | Argomento fornito non valido. Questo errore viene restituito se il parametro dwIoControlCode non è un comando valido o un parametro di input specificato non è accettabile oppure il comando non è applicabile al tipo di socket specificato. |
WSAENETDOWN | Rete inattiva rilevata durante l'operazione del socket. Questo errore viene restituito se il sottosistema di rete non è riuscito. |
WSAENOTSOCK | Un'operazione è stata tentata su un elemento che non è un socket. Questo errore viene restituito se il descrittore s non è un socket. |
WSAEOPNOTSUPP | L'operazione tentata non è supportata per il tipo di oggetto a cui viene fatto riferimento. Questo errore viene restituito se il comando IOCTL specificato non è supportato. Questo errore viene restituito anche se il SIO_ACQUIRE_PORT_RESERVATION IOCTL non è supportato dal provider di trasporto. Questo errore viene restituito anche quando viene eseguito un tentativo di utilizzo del SIO_ACQUIRE_PORT_RESERVATION IOCTL in un socket diverso da UDP o TCP. |
Commenti
Il SIO_ACQUIRE_PORT_RESERVATION IOCTL è supportato in Windows Vista e versioni successive del sistema operativo.
Le applicazioni e i servizi che devono riservare le porte rientrano in due categorie. La prima categoria include componenti che necessitano di una determinata porta nell'ambito dell'operazione. Tali componenti preferiscono in genere specificare la porta richiesta in fase di installazione (ad esempio in un manifesto dell'applicazione). La seconda categoria include componenti che richiedono qualsiasi porta o blocco disponibile di porte in fase di esecuzione. Queste due categorie corrispondono a richieste di prenotazione delle porte con caratteri jolly e specifiche. Le richieste di prenotazione specifiche possono essere persistenti o in fase di esecuzione, mentre le richieste di prenotazione con porta jolly sono supportate solo in fase di esecuzione.
Il SIO_ACQUIRE_PORT_RESERVATION IOCTL viene usato per richiedere una prenotazione di runtime per un blocco di porte TCP o UDP. Per le prenotazioni delle porte di runtime, il pool di porte richiede che le prenotazioni vengano usate dal processo in cui è stata concessa la prenotazione. Le prenotazioni delle porte di runtime durano solo fino alla durata del socket in cui è stato chiamato il SIO_ACQUIRE_PORT_RESERVATION IOCTL. Al contrario, le prenotazioni di porte persistenti create usando la funzione CreatePersistentTcpPortReservation o CreatePersistentUdpPortReservation possono essere usate da qualsiasi processo con la possibilità di ottenere prenotazioni persistenti.
Dopo aver ottenuto una prenotazione della porta TCP o UDP di runtime, un'applicazione può richiedere assegnazioni di porta dalla prenotazione della porta aprendo un socket TCP o UDP, quindi chiamando la funzione WSAIoctl specificando la SIO_ASSOCIATE_PORT_RESERVATION IOCTL e passando il token di prenotazione prima di inviare una chiamata alla funzione di associazione nel socket.
Se entrambi i parametri lpOverlapped e lpCompletionRoutine sono NULL, il socket in questa funzione verrà considerato come socket non sovrapposto. Per un socket non sovrapposto, i parametri lpOverlapped e lpCompletionRoutine vengono ignorati, ad eccezione del fatto che la funzione può bloccare se socket s è in modalità di blocco. Se socket s è in modalità non bloccabile, questa funzione continuerà a bloccarsi poiché questa particolare modalità IOCTL non supporta la modalità di blocco.
Per i socket sovrapposti, le operazioni che non possono essere completate immediatamente verranno avviate e il completamento verrà indicato in un secondo momento.
Qualsiasi IOCTL può bloccare a tempo indefinito, a seconda dell'implementazione del provider di servizi. Se l'applicazione non può tollerare il blocco in una chiamata di funzione WSAIoctl o WSPIoctl , è consigliabile che le operazioni di I/O sovrapposte siano consigliate per IOCTL che sono particolarmente probabili bloccare.
Il SIO_ACQUIRE_PORT_RESERVATION IOCTL può avere esito negativo con WSAEINTR o WSA_OPERATION_ABORTED nei casi seguenti:
- La richiesta viene annullata da I/O Manager.
- Il socket è chiuso.
Esempio
L'esempio seguente acquisisce una prenotazione della porta di runtime, quindi crea un socket e alloca una porta dalla prenotazione della porta di runtime per il socket e quindi chiude il socket e rilascia la prenotazione della porta di runtime.
#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;
}
Vedi anche
CreatePersistentTcpPortReservation
CreatePersistentUdpPortReservation
DeletePersistentTcpPortReservation
DeletePersistentUdpPortReservation
INET_PORT_RESERVATION_INSTANCE
LookupPersistentTcpPortReservation
LookupPersistentUdpPortReservation