Share via


código de controle SIO_ACQUIRE_PORT_RESERVATION

Descrição

O código de controle SIO_ACQUIRE_PORT_RESERVATION adquire uma reserva de runtime para um bloco de portas TCP ou UDP.

Para executar essa operação, chame a função WSAIoctl ou WSPIoctl com os parâmetros a seguir.

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

Um descritor que identifica um soquete.

Dwiocontrolcode

O código de controle da operação. Use SIO_ACQUIRE_PORT_RESERVATION para esta operação.

Lpvinbuffer

Um ponteiro para o buffer de entrada. Esse parâmetro contém um ponteiro para uma estrutura INET_PORT_RANGE que especifica o número do ponto de partida e o número de portas a serem reservadas.

Cbinbuffer

O tamanho, em bytes, do buffer de entrada. Esse parâmetro deve ser o tamanho da estrutura INET_PORT_RANGE .

Lpvoutbuffer

Um ponteiro para o buffer de saída. Na saída bem-sucedida, esse parâmetro contém um ponteiro para uma estrutura INET_PORT_RESERVATION_INSTANCE .

cbOutBuffer

O tamanho, em bytes, do buffer de saída. Esse parâmetro deve ter pelo menos o tamanho da estrutura INET_PORT_RESERVATION_INSTANCE .

Lpcbbytesreturned

Um ponteiro para uma variável que recebe o tamanho, em bytes, dos dados armazenados no buffer de saída.

Se o buffer de saída for muito pequeno, a chamada falhará, WSAGetLastError retornará WSAEINVAL e o parâmetro lpcbBytesReturned apontará para um valor DWORD igual a zero.

Se lpOverlapped for NULL, o valor DWORD apontado pelo parâmetro lpcbBytesReturned retornado em uma chamada bem-sucedida não poderá ser zero.

Se o parâmetro lpOverlapped não for NULL para soquetes sobrepostos, as operações que não puderem ser concluídas imediatamente serão iniciadas e a conclusão será indicada posteriormente. O valor DWORD apontado pelo parâmetro lpcbBytesReturned retornado pode ser zero, pois o tamanho dos dados armazenados não pode ser determinado até que a operação sobreposta seja concluída. A conclusão final status pode ser recuperada quando o método de conclusão apropriado é sinalizado quando a operação é concluída.

lpvOverlapped

Um ponteiro para uma estrutura WSAOVERLAPPED .

Se o soquete s tiver sido criado sem o atributo sobreposto, o parâmetro lpOverlapped será ignorado.

Se s tiver sido aberto com o atributo sobreposto e o parâmetro lpOverlapped não for NULL, a operação será executada como uma operação sobreposta (assíncrona). Nesse caso, o parâmetro lpOverlapped deve apontar para uma estrutura WSAOVERLAPPED válida.

Para operações sobrepostas, a função WSAIoctl ou WSPIoctl retorna imediatamente e o método de conclusão apropriado é sinalizado quando a operação é concluída. Caso contrário, a função não retornará até que a operação seja concluída ou ocorra um erro.

Lpcompletionroutine

Tipo: _In_opt_ LPWSAOVERLAPPED_COMPLETION_ROUTINE

Um ponteiro para a rotina de conclusão chamado quando a operação foi concluída (ignorado para soquetes não sobrepostos).

lpThreadId

Um ponteiro para uma estrutura WSATHREADID a ser usada pelo provedor em uma chamada subsequente para WPUQueueApc. O provedor deve armazenar a estrutura WSATHREADID referenciada (não o ponteiro para o mesmo) até que a função WPUQueueApc retorne.

Nota Esse parâmetro se aplica somente à função WSPIoctl .

Lperrno

Um ponteiro para o código de erro.

Nota Esse parâmetro se aplica somente à função WSPIoctl .

Valor retornado

Se a operação for concluída com êxito, a função WSAIoctl ou WSPIoctl retornará zero.

Se a operação falhar ou estiver pendente, a função WSAIoctl ou WSPIoctl retornará SOCKET_ERROR. Para obter informações de erro estendidas, chame WSAGetLastError.

Código do erro Significado
WSA_IO_PENDING A operação de E/S sobreposta está em andamento. Esse valor será retornado se uma operação sobreposta tiver sido iniciada com êxito e a conclusão for indicada posteriormente.
WSA_OPERATION_ABORTED A operação de E/S foi anulada devido ao encerramento de um thread ou a uma solicitação de aplicativo. Esse erro será retornado se uma operação sobreposta tiver sido cancelada devido ao fechamento do soquete ou à execução do SIO_FLUSH comando IOCTL.
WSAEFAULT O sistema detectou um endereço de ponteiro inválido ao tentar usar um argumento de ponteiro em uma chamada. Esse erro é retornado do parâmetro lpvInBuffer, lpvoutBuffer, lpcbBytesReturned, lpOverlapped ou lpCompletionRoutine não está totalmente contido em uma parte válida do espaço de endereço do usuário.
WSAEINPROGRESS Uma operação de bloqueio está atualmente em execução. Esse erro será retornado se a função for invocada quando um retorno de chamada estiver em andamento.
WSAEINTR Uma operação de bloqueio foi interrompida por uma chamada para WSACancelBlockingCall. Esse erro será retornado se uma operação de bloqueio tiver sido interrompida.
WSAEINVAL Foi fornecido um argumento inválido. Esse erro será retornado se o parâmetro dwIoControlCode não for um comando válido ou se um parâmetro de entrada especificado não for aceitável ou se o comando não for aplicável ao tipo de soquete especificado.
WSAENETDOWN Uma operação de soquete encontrou uma rede inoperante. Esse erro será retornado se o subsistema de rede falhar.
WSAENOTSOCK Uma operação foi tentada em algo que não é um soquete. Esse erro será retornado se o descritor s não for um soquete.
WSAEOPNOTSUPP Não há suporte para a tentativa de operação para o tipo de objeto referenciado. Esse erro será retornado se não houver suporte para o comando IOCTL especificado. Esse erro também será retornado se o SIO_ACQUIRE_PORT_RESERVATION IOCTL não tiver suporte do provedor de transporte. Esse erro também é retornado quando uma tentativa de usar o SIO_ACQUIRE_PORT_RESERVATION IOCTL é feita em um soquete diferente de UDP ou TCP.

Comentários

O SIO_ACQUIRE_PORT_RESERVATION IOCTL é compatível com o Windows Vista e versões posteriores do sistema operacional.

Aplicativos e serviços que precisam reservar portas se enquadram em duas categorias. A primeira categoria inclui componentes que precisam de uma porta específica como parte de sua operação. Esses componentes geralmente preferem especificar a porta necessária no momento da instalação (em um manifesto do aplicativo, por exemplo). A segunda categoria inclui componentes que precisam de qualquer porta disponível ou bloco de portas em runtime. Essas duas categorias correspondem a solicitações de reserva de porta curinga e específicas. Solicitações de reserva específicas podem ser persistentes ou runtime, enquanto as solicitações de reserva de porta curinga só têm suporte no runtime.

O SIO_ACQUIRE_PORT_RESERVATION IOCTL é usado para solicitar uma reserva de runtime para um bloco de portas TCP ou UDP. Para reservas de porta de runtime, o pool de portas exige que as reservas sejam consumidas do processo em cujo soquete a reserva foi concedida. As reservas de porta de runtime duram apenas o tempo de vida do soquete no qual o SIO_ACQUIRE_PORT_RESERVATION IOCTL foi chamado. Por outro lado, as reservas de porta persistentes criadas usando a função CreatePersistentTcpPortReservation ou CreatePersistentUdpPortReservation podem ser consumidas por qualquer processo com a capacidade de obter reservas persistentes.

Depois que uma reserva de porta TCP ou UDP de runtime tiver sido obtida, um aplicativo poderá solicitar atribuições de porta da reserva de porta abrindo um soquete TCP ou UDP e, em seguida, chamando a função WSAIoctl especificando o SIO_ASSOCIATE_PORT_RESERVATION IOCTL e passando o token de reserva antes de emitir uma chamada para a função de associação no soquete.

Se os parâmetros lpOverlapped e lpCompletionRoutine forem NULL, o soquete nessa função será tratado como um soquete não sobreposto. Para um soquete não sobreposto, os parâmetros lpOverlapped e lpCompletionRoutine são ignorados, exceto que a função pode bloquear se o soquete s estiver no modo de bloqueio. Se o soquete s estiver no modo sem bloqueio, essa função ainda será bloqueada, pois esse IOCTL específico não dá suporte ao modo sem bloqueio.

Para soquetes sobrepostos, as operações que não podem ser concluídas imediatamente serão iniciadas e a conclusão será indicada posteriormente.

Qualquer IOCTL pode bloquear indefinidamente, dependendo da implementação do provedor de serviços. Se o aplicativo não puder tolerar o bloqueio em uma chamada de função WSAIoctl ou WSPIoctl , a E/S sobreposta será aconselhada para IOCTLs que são especialmente propensas a bloquear.

O SIO_ACQUIRE_PORT_RESERVATION IOCTL pode falhar com WSAEINTR ou WSA_OPERATION_ABORTED nos seguintes casos:

  • A solicitação é cancelada pelo Gerenciador de E/S.
  • O soquete está fechado.

Exemplos

O exemplo a seguir adquire uma reserva de porta de runtime, cria um soquete e aloca uma porta da reserva de porta de runtime para o soquete e, em seguida, fecha o soquete e libera a reserva de porta de 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;
}

Confira também

Aceitar

Ligar

CreatePersistentTcpPortReservation

CreatePersistentUdpPortReservation

DeletePersistentTcpPortReservation

DeletePersistentUdpPortReservation

INET_PORT_RANGE

INET_PORT_RESERVATION_INSTANCE

LookupPersistentTcpPortReservation

LookupPersistentUdpPortReservation

SIO_ASSOCIATE_PORT_RESERVATION

SIO_RELEASE_PORT_RESERVATION

soquete

Wsagetlasterror

Wsagetoverlappedresult

Wsaioctl

WSAOVERLAPPED

WSASocketA

WSASocketW