Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: Kaxperday en 14 Junio 2016, 19:09 pm



Título: WSAError: 10004 ; Blocking sockets
Publicado por: Kaxperday en 14 Junio 2016, 19:09 pm
Hola a todos,

Bueno estoy trabajando con un servidor proxy HTTP y parece que hay problemas con los sockets al hacer accept(), antes de nada decir que uso el navegador para conectar al servidor, decir que es un proxy recibe petición del navegador carga la peticion y la manda al servidor con CURL, y mando la respuesta al socket.

WSAEINTR 10004 Interrupted function call: A blocking operation was interrupted by a call to WSACancelBlockingCall.

Esto quiere decir que alguien ha llamado llamado a WSACancelBlockingCall y las funciones de espera asociadas a sockets no funcionan como recv o accept ya que son funciones que se bloquean hasta obtener una respuesta a no ser que se las ponga un temporizador máximo de espera, si se llama a esta función esa espera desaparece haciéndolas inútiles.

El código:

Código
  1. void Run(std::string serverIP, UINT serverPort)
  2. {
  3. WSADATA wsa;
  4. SOCKET serverSocket;
  5. sockaddr_in serverAddr;
  6.  
  7. WSAStartup(MAKEWORD(2, 0), &wsa);
  8.  
  9. if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) != SOCKET_ERROR)
  10. {
  11. serverAddr.sin_family = AF_INET;
  12. serverAddr.sin_port = htons(serverPort);
  13. serverAddr.sin_addr.s_addr = inet_addr(serverIP.c_str());
  14.  
  15. if (::bind(serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) != SOCKET_ERROR)
  16. {
  17. if (listen(serverSocket, MAXIMUM_VICTIMS) != SOCKET_ERROR)
  18. {
  19. SOCKET victimSocket;
  20. sockaddr_in victimAddr;
  21. victimAddr.sin_family = AF_INET;
  22. INT len = sizeof(victimAddr);
  23.  
  24.  
  25. while (status != DISABLE)
  26. {
  27. victimSocket = accept(serverSocket, (sockaddr*)&victimAddr, &len);
  28.  
  29. if (victimSocket != INVALID_SOCKET)
  30. {
  31. std::thread t(HTTPSession, victimSocket, inet_ntoa(victimAddr.sin_addr), status);
  32. t.detach();
  33. }
  34.  
  35. }
  36.  
  37. }
  38. }
  39. closesocket(serverSocket);
  40. }
  41.  
  42. WSACleanup();
  43.  
  44. }
  45.  

Las 2 primeras requests del cliente las recibe y responde con éxito pero a partir de la segunda request tras enviar la respuesta llama a WSACancelBlockingCall, ¿porque? ¿cómo evitarlo?.

Una vez que sale el error 10004 el bucle itera produciendo errores 10093 (WSANOTINITIALISED).

Puede que sea llamada en HTTPSession:

Código
  1. void HTTPSession(SOCKET victimSocket, std::string victimIP, STATUS& controller)
  2. {
  3. CHAR headerBuffer[8192];
  4. memset(headerBuffer, '\0', 8192);
  5.  
  6. INT rlen = recv(victimSocket, headerBuffer, 8192, NULL);
  7. ...
  8. }
  9.  

Reading: http://www.sockets.com/winsock.htm#CancelBlockingCall

Estoy probando a ponerlo en blocking mode de nuevo con:
Código
  1. ULONG iMode = 0;//blocking mode
  2. ioctlsocket(victimSocket, FIONBIO, &iMode);
  3.  
Pero falla de nuevo por el error 10004.

Saludos.

Edito: Bueno, decir que esta parcialmente arreglado con una chapuza que trataré de mejorar, lo que vengo a hacer es reestablecer el modo block despues de cada accept para el socket "victimSocket", así si al llamar al thread y hacer el recv() se llama a cancelblocking rapidamente se reestablecera tras obtener la respuesta de recv. Hay que llamar a WSAStartup pues la llamada a cancelblocking llama a WSACleanup().

Código
  1. ULONG iMode = 0;//block mode
  2. while (status != DISABLE)
  3. {
  4. victimSocket = accept(serverSocket, (sockaddr*)&victimAddr, &len);
  5.  
  6. if (victimSocket != INVALID_SOCKET)
  7. {
  8. std::thread t(HTTPSession, victimSocket, inet_ntoa(victimAddr.sin_addr), status);
  9. t.detach();
  10. }
  11.  
  12. WSAStartup(MAKEWORD(2, 0), &wsa);
  13. INT iResult = ioctlsocket(victimSocket, FIONBIO, &iMode);
  14. if (iResult != NO_ERROR)
  15. printf("ioctlsocket failed with error: %ld %d\n", iResult, GetLastError());
  16. }
  17.  

PD: He probado a hacerlo solo cuando de error y no funciona, sería curar con esto prevenimos siempre pero evidentemente no me convence tener que llamar a WSAStartup en un bucle, buscaré mejores alternativas..

Edito otra vez: NO hace falta usar ioctlsocket para ponerlo en modo block, solo con llamar a WSAStartup ya funciona y no da error :""""(, la cosa es que parece que para cada socket hay que llamar a WSAStartup así que meteré la llamada en HTTPSession.


Título: Re: WSAError: 10004 ; Blocking sockets
Publicado por: ivancea96 en 15 Junio 2016, 18:38 pm
Basta llamar WSAStartup 1 vez por programa, salvo que realmente necesites hacerlo varias veces.
Si llamarlo más veces te soluciona el problema, ten en cuenta que el verdadero error ha de seguir ahí.


Título: Re: WSAError: 10004 ; Blocking sockets
Publicado por: Kaxperday en 16 Junio 2016, 07:56 am
Hola ivancea,

Parece que ya está solucionado eramás bien un despiste, pues en HTTPSession al final de la función llamaba a WSACleanup() y por eso daba  el error de nonblocking sockets (que lo debería de llamar WSACleanup()) y tras desbloquear los sockets, desinicializaba winsock y tenía que llamar de nuevo a WSAStartup, así que ya sabeis poned igual numero de WSAStartup y de WSACleanup para no llevaros sustos XD.

Saludos y gracias por la respuesta.