سؤال

i'm making a small IRC server, but I've come across a problem; upon trying to listen to the socket, i get error 10022 (Invalid Argument).

The error also appears on accept(), but this is because the socket isn't listening (the problem i'm posting about).

I didn't include the accept function because i feel it isn't necessary and would be adding pointless code.

#include <iostream>
#include <ws2tcpip.h>
#include <winsock2.h>
#include <thread>
#include <string>
#pragma comment(lib, "Ws2_32.lib")
#define maxConnections 10
class Server
{
        struct sockaddr_storage their_addr;
        struct addrinfo hints, *res;
        struct addrinfo *servinfo;
    int status;
    SOCKET sock;
public:
    void Start(const char *port);
};

void Server::Start(const char *port)
{
    WSADATA WSAData;
    if (WSAStartup(MAKEWORD(2, 0), &WSAData) != 0)
    {
        std::cout << "[ERROR]: " << GetLastError() << ".\n";
    }
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    status = getaddrinfo(NULL, port, &hints, &res);
    sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (sock == SOCKET_ERROR)
    {
        std::cout << "[ERROR]: " << WSAGetLastError() << "Bad Socket.\n";
    }
    bind(sock, res->ai_addr, res->ai_addrlen);

Error:

    if (listen(sock, maxConnections) == SOCKET_ERROR)
    {
        std::cout << "[ERROR]: " << WSAGetLastError() << " Listening Failed.\n";
    }

The code above details the socket creation and binding, all of which are successful (though not necessarily right). The socket creation including 'NULL' might be the issue.

Thanks :)

هل كانت مفيدة؟

المحلول

WSAStartup() and getaddrinfo() do not use (WSA)GetLastError(), they directly return the actual error code instead. You are not accounting for that in your error messages.

socket() returns INVALID_SOCKET on failure, not SOCKET_ERROR.

When using getaddrinfo() to create a listening socket, you should specify AI_PASSIVE in the addrinfo.ai_flags field of the hints parameter. That will fill the output addrinfo with data that is suitable to pass to bind().

Try something more like this:

class Server
{
private:
    bool winsockStarted;
    SOCKET sock;
    ...
public:
    Server();
    ~Server();
    bool Start(const char *port);
    void Stop();
    ...
};

Server::Server()
    : sock(INVALID_SOCKET), winsockStarted(false)
{
    WSADATA WSAData = {0};
    int status = WSAStartup(MAKEWORD(2, 0), &WSAData);
    if (status != 0)
        std::cout << "[ERROR]: " << status << " Unable to start Winsock." << std::endl;
    else
        winsockStarted = true;
}

Server::~Server()
{
    Stop();

    if (winsockStarted)
        WSACleanup();
}

bool Server::Start(const char *port)
{
    Stop();

    struct addrinfo hints = {0};
    struct addrinfo *res = NULL;

    hints.ai_flags = AI_PASSIVE;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    int status = getaddrinfo(NULL, port, &hints, &res);
    if (status != 0)
    {
        std::cout << "[ERROR]: " << status << " Unable to get address info for Port " << port << "." << std::endl;
        return false;
    }

    SOCKET newsock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (newsock == INVALID_SOCKET)
    {
        std::cout << "[ERROR]: " << WSAGetLastError() << " Unable to create Socket." << std::endl;
        freeaddrinfo(res);
        return false;
    }

    if (bind(newsock, res->ai_addr, res->ai_addrlen) == SOCKET_ERROR)
    {
        std::cout << "[ERROR]: " << WSAGetLastError() << " Unable to bind Socket." << std::endl;
        freeaddrinfo(res);
        closesocket(newsock);
        return false;
    }

    freeaddrinfo(res);

    if (listen(newsock, maxConnections) == SOCKET_ERROR)
    {
        std::cout << "[ERROR]: " << WSAGetLastError() << " Unable to Listen on Port " << port << "." << std::endl;
        closesocket(newsock);
        return false;
    }

    sock = newsock;
    return true;
}

void Server::Stop()
{
    if (sock != INVALID_SOCKET)
    {
        closesocket(sock);
        sock = INVALID_SOCKET;
    }
}

نصائح أخرى

I reread my code and realized that i need to add a check here

status = getaddrinfo(NULL, port, &hints, &res); 

I changed it to

if (status = getaddrinfo(NULL, port, &hints, &res) != 0)
{
    std::cout << "[ERROR]: " << WSAGetLastError() << "Get Address Info failed.\n";
}

and startup was successful.

If someone could explain why, i'll improve my answer.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top