С++ WinSock2: WSA_INVALID_HANDLE при вызове connect()

Добрый день!

Я немного опытный программист на языках более высокого уровня, но я впервые погружаюсь в код сокетов на языках более низкого уровня, поэтому, пожалуйста, потерпите меня.

Кажется, я получаю сообщение об ошибке при вызове connect(). В моей основной функции WSAGetLastError() печатает, что это ошибка номер 6, которая, согласно MSDN, равна WSA_INVALID_HANDLE. Это кажется странным, поскольку в Страница MSDN для функции connect() (если только я не ослепну), и мои поиски в Google не дают результатов

Я использую пользовательскую структуру socket_t, поскольку мой код предназначен (в конечном итоге) для кроссплатформенности. Функция socket_connect() вызывается из основной кодовой страницы.

socket_t определение:

typedef struct
{
    //windows-specific
    SOCKADDR_IN *addr_in;
    u_long mode;
    SOCKET socket;//acutal SOCKET structure

    // General
    bool listening;//set to true if actively listening
    bool thread_terminate;//when boolean is set to true, listening thread terminates
    void (*error_callback) (int);
    http_response_t * response;
} socket_t;

socket_connect() функция:

//see socket_t definition in socket.h
//returns 0 on success, SOCKET_ERROR on WinSock failure, positive error code on ANSI DNS failure
int socket_connect(socket_t * sock, char * addr, int port)
{
    //bear in mind sock is the custom socket_t structure.  sock->socket is the actual SOCKET structure.
    //pardon the nomenclature.  rookie code.

    //DNS lookup structures
    struct addrinfo     * res           = NULL;// Result of the getaddrinfo() call
    struct sockaddr_in  * sockaddr_v4   = NULL;// IPv4 sockaddr structure

    // So-called "hints" structure detailed in the getaddrinfo() MSDN page.
    // I guess it contains information for the DNS lookup.
    struct addrinfo hints;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family     = AF_UNSPEC;
    hints.ai_socktype   = SOCK_STREAM;
    hints.ai_protocol   = IPPROTO_TCP;

    //Perform DNS lookup
    DWORD getaddrinfo_res = getaddrinfo(addr, "80\0", &hints, &res);//hard-code Port number for now...
    if(getaddrinfo_res != 0) return getaddrinfo_res;//positive DNS error code

            //debug information
    std::cout << "DNS lookup responses:" << std::endl;
    //for each
    int i = 0;//counter
    for(struct addrinfo * ptr = res; ptr != NULL; ptr = ptr->ai_next)
    {
        std::cout << "Response number " << i + 1 << std::endl;
        std::cout << "Flags: " << ptr->ai_flags << std::endl;

        std::cout << "Family: ";
        switch(ptr->ai_family)
        {
        case AF_INET:
            sockaddr_v4 = (struct sockaddr_in *) ptr->ai_addr;//set current address
            sock->addr_in = sockaddr_v4;//set socket address

            std::cout << "AF_INET (IPv4)" << std::endl;
            std::cout << "Addr: " << inet_ntoa(sockaddr_v4->sin_addr) << std::endl;
            break;
        case AF_UNSPEC:
            std::cout << "UNSPECIFIED" << std::endl;
            break;
        default:
            std::cout << "UNKNOWN\t(" << ptr->ai_family << ")" << std::endl;
            break;
        }

        i++;
    }

    //initialize actual SOCKET
    sock->socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);// TCP/IP, stream-oriented, and TCP rather than UDP; respectively
    if(sock->socket == INVALID_SOCKET) return SOCKET_ERROR;

    //actual connection
    std::cout << WSAGetLastError() << std::endl;
    int connect_res = connect(sock->socket, (SOCKADDR *) sockaddr_v4, sizeof(sockaddr_v4));///have to convert SOCKADDR_IN to a SOCKADDR pointer here.  Not sure why.
    if(connect_res == SOCKET_ERROR) return SOCKET_ERROR;

    //make nonblocking
    /*
    sock->mode = 1;
    int ioctl = ioctlsocket(sock->socket, FIONBIO, &(sock->mode));//I/O Control Socket.  Not sure what FIONBIO means.  pointer to sock->mode = 1 ensures nonblockingness.
    if(ioctl == SOCKET_ERROR) return SOCKET_ERROR;
    */// (include this?)

    return 0;
}

socket_connect() вызов функции:

int connect_res = conley::socket_connect(sock, "www.google.com", 80);
if(connect_res > 0) std::cout << "DNS ERR " << connect_res << std::endl << std::endl;
if(connect_res < 0) std::cout << "CONNECT ERR " << WSAGetLastError() << std::endl << std::endl;
if(connect_res == 0) std::cout << "Connected" << std::endl << std::endl;

Спасибо за уделенное время! - Джейк


person Jake    schedule 15.09.2013    source источник
comment
Сначала банальные вопросы. Правильно ли вы инициализировали WinSock, используя WSAStartup() ?   -  person WhozCraig    schedule 15.09.2013
comment
@WhozCraig Да, я так думаю.   -  person Jake    schedule 15.09.2013


Ответы (1)


Вы передаете неправильный размер sockaddr_in при вызове connect.

Измените это:

int connect_res = connect(sock->socket, (SOCKADDR *) sockaddr_v4, sizeof(sockaddr_v4));
//                                                            wrong size ^^^^^^^^^^^

К этому:

int connect_res = connect(sock->socket, (SOCKADDR *) sockaddr_v4, sizeof(*sockaddr_v4));
//                                                            right size  ^^^^^^^^^^^

Кроме того, в вашей программе есть другая ошибка, а именно постоянство возвращаемого указателя getaddrinfo() - в вашей структуре sock. Это должно быть скопировано по значению в память, принадлежащую sock. Это будет работать с этим образцом, потому что он очень изолирован, но его следует изменить.

person WhozCraig    schedule 15.09.2013
comment
А, теперь имеет смысл. Спасибо! - person Jake; 15.09.2013