Here is my first question in this great website.
I am writing a simple server, obtaining the port number form the user:
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <string>
#include <cstring>
class socketConexion {
private:
WSADATA wsaData;
int iResultado;
SOCKET socketServidor = INVALID_SOCKET; socket servidor
SOCKET socketCliente = INVALID_SOCKET;
struct sockaddr *clienteSockaddr;
struct addrinfo *socketResultado = NULL;
struct addrinfo datosServidor;
std::string puertoUsuario;
char clienteIPV4[LONG_IPV4];
public:
int iniciarWinsock () {
iResultado = WSAStartup(MAKEWORD(2,2), &wsaData);
printf ("Inicializando Winsock2 \n");
if (iResultado != 0) {
printf ("Error al iniciar Winsock2: %d\n", iResultado);
return 1;
else {
printf ("Winsock2 Inicializado\n");
return 0;
}
}
int obtenerDirServidor () {
printf ("Introduzca puerto: ");
std::cin >> puertoUsuario;
printf ("Obteniendo datos de servidor.\n");
ZeroMemory(&datosServidor, sizeof(datosServidor));
datosServidor.ai_family = AF_INET;
datosServidor.ai_socktype = SOCK_STREAM;
datosServidor.ai_protocol = IPPROTO_TCP;
datosServidor.ai_flags = AI_PASSIVE;
iResultado = getaddrinfo(NULL, (const char*)puertoUsuario.c_str(), &datosServidor, &socketResultado);
if (iResultado != 0) {
printf ("Error al obtener dirección de servidor: %d\n", iResultado);
WSACleanup();
return 1;
}
else {
printf ("Dirección de servidor obtenida.\n");
return 0;
}
}
int socketBind () {
socketServidor = socket(socketResultado->ai_family, socketResultado->ai_socktype, socketResultado->ai_protocol);
if (socketServidor == INVALID_SOCKET) {
printf ("Error al crear socket: %d\n", WSAGetLastError ());
freeaddrinfo (socketResultado);
WSACleanup();
return 1;
}
else {
printf ("Socket creado correctamente.\n");
return 0;
}
iResultado = bind(socketServidor, socketResultado->ai_addr, (int)socketResultado->ai_addrlen);
if (iResultado == SOCKET_ERROR) {
printf ("Error al direccionar socket: %d\n", WSAGetLastError());
freeaddrinfo (socketResultado);
closesocket(socketServidor);
WSACleanup();
return 1;
}
else {
printf ("Socket direccionado correctamente. \n");
return 0;
}
freeaddrinfo (socketResultado);
}
int socketListen (){
iResultado = listen(socketServidor, SOMAXCONN);
if (iResultado == SOCKET_ERROR) {
printf ("Error al poner socket a la escucha socket: %d\n", WSAGetLastError());
closesocket(socketServidor);
WSACleanup();
return 1;
}
else {
printf ("Esperando conexión..... %d\n");
return 0;
}
.....
I get the error 10022 when calling listen function, and I can't see the invalid argument I am passing to the function.
Error code 10022 is WSAEINVAL
:
Invalid argument.
Some invalid argument was supplied (for example, specifying an invalid level to thesetsockopt
function). In some instances, it also refers to the current state of the socket—for instance, callingaccept
on a socket that is not listening.
Per the listen()
documentation:
Return value
If no error occurs,
listen
returns zero. Otherwise, a value ofSOCKET_ERROR
is returned, and a specific error code can be retrieved by callingWSAGetLastError
....
WSAEINVAL
The socket has not been bound withbind
In your socketBind()
method, if socket()
is successful, you are calling return
before you call bind()
, so the socket is never bound. You need to remove the return
statement in the 1st else
block. Also, if bind()
is successful, the 2nd else
block is calling return
before calling freeaddrinfo()
, so you need to fix that as well.
Try this:
int socketBind () {
socketServidor = socket(socketResultado->ai_family, socketResultado->ai_socktype, socketResultado->ai_protocol);
if (socketServidor == INVALID_SOCKET) {
printf ("Error al crear socket: %d\n", WSAGetLastError ());
freeaddrinfo (socketResultado);
WSACleanup();
return 1;
}
printf ("Socket creado correctamente.\n");
iResultado = bind(socketServidor, socketResultado->ai_addr, (int)socketResultado->ai_addrlen);
if (iResultado == SOCKET_ERROR) {
printf ("Error al direccionar socket: %d\n", WSAGetLastError());
freeaddrinfo (socketResultado);
closesocket(socketServidor);
WSACleanup();
return 1;
}
printf ("Socket direccionado correctamente. \n");
freeaddrinfo (socketResultado);
return 0;
}
That being said, your class is not doing a very good job of cleanup in general. I would suggest something more C++-like (using RAII, throwing exceptions on errors, etc):
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <string>
#include <system_error>
#include <memory>
class socketError : public std::system_error
{
public:
explicit socketError(int err, const std::string &msg)
: std::system_error(err, std::system_category(), msg + ": " + std::to_string(err))
{
}
};
void throwSocketError(int err, const std::string &msg)
{
std::cout << msg << ": " << err << std::endl;
throw socketError(err, msg);
}
class wsaInit
{
public:
wsaInit() {
int iResultado = WSAStartup(MAKEWORD(2,2), &wsaData);
printf ("Inicializando Winsock2 \n");
if (iResultado != 0)
throwSocketError(iResultado, "Error al iniciar Winsock2");
printf ("Winsock2 Inicializado\n");
}
~wsaInit() {
WSACleanup();
}
wsaInit(const wsaInit &) = delete;
wsaInit& operator=(const wsaInit &) = delete;
};
class socketWrapper
{
private:
SOCKET sckt;
public:
socketWrapper() : sckt(INVALID_SOCKET) {}
explicit socketWrapper(SOCKET initialSocket) : sckt(initialSocket) {}
~socketWrapper() { reset(); }
socketWrapper(const socketWrapper &) = delete;
socketWrapper& operator=(const socketWrapper &) = delete;
void reset(SOCKET newSocket = INVALID_SOCKET) { if (sckt != INVALID_SOCKET) closesocket(sckt); sckt = newSocket; }
operator SOCKET() const { return sckt; }
bool operator !() const { return (sckt == INVALID_SOCKET); }
};
class socketConexion {
private:
wsaInit wsa;
socketWrapper socketServidor;
socketWrapper socketCliente;
std::unique_ptr<struct addrinfo> socketResultado;
...
public:
socketConexion(const socketConexion &) = delete;
socketConexion& operator=(const socketConexion &) = delete;
void obtenerDirServidor() {
socketResultado.reset();
printf ("Introduzca puerto: ");
std::string puertoUsuario;
std::cin >> puertoUsuario;
printf ("Obteniendo datos de servidor.\n");
struct addrinfo datosServidor;
ZeroMemory(&datosServidor, sizeof(datosServidor));
datosServidor.ai_family = AF_INET;
datosServidor.ai_socktype = SOCK_STREAM;
datosServidor.ai_protocol = IPPROTO_TCP;
datosServidor.ai_flags = AI_PASSIVE;
struct addrinfo *pResultado;
int iResultado = getaddrinfo(NULL, puertoUsuario.c_str(), &datosServidor, &pResultado);
if (iResultado != 0)
throwSocketError(iResultado, "Error al obtener dirección de servidor");
socketResultado.reset(pResultado);
std::cout << "Dirección de servidor obtenida." << std::endl;
}
void socketBind () {
socketServidor.reset();
if (!socketResultado)
obtenerDirServidor();
socketServidor.reset(socketResultado->ai_family, socketResultado->ai_socktype, socketResultado->ai_protocol));
if (!socketServidor) {
int iError = WSAGetLastError();
socketResultado.reset();
throwSocketError(iError, "Error al crear socket");
}
printf("Socket creado correctamente.\n");
int iResultado = ::bind(socketServidor, socketResultado->ai_addr, (int)socketResultado->ai_addrlen);
if (iResultado == SOCKET_ERROR) {
iResultado = WSAGetLastError();
socketResultado.reset();
throwSocketError(iResultado, "Error al direccionar socket");
}
socketResultado.reset();
printf ("Socket direccionado correctamente. \n");
}
void socketListen() {
if (!socketServidor)
socketBind();
int iResultado = listen(socketServidor, SOMAXCONN);
if (iResultado == SOCKET_ERROR)
throwSocketError(WSAGetLastError(), "Error al poner socket a la escucha socket");
printf ("Esperando conexión.....\n");
}
...
};