accept() returns SOCKET_ERROR without connection request - c

I'm making an application to test TCP connections and study network protocols. The same application is Client or Server depending the user parameters.
I'm developing it on Windows 10 using Dev-Cpp 5.11.
But, when I try to run it like a server I get the following error:
When it call accept():
accept() returns SOCK_ERROR.
WSAGetLastError() return Bad Address (until listen() it returns NULL)
The application returns immediately, there is no client connection request or delay waiting connection request.
The output is:
:: SERVER MODE
:: PORT: 2020
:: Time Limit receiving: 1000ms
:: WSA Version: 0202
:: Criando SOCKET: OK
:: SOCKET Binding: OK
:: LISTENING . . .
WSA Error: Bad address
Socket Value: -1
ERRO 0 [Bad address]
--------------------------------
Process exited after 0.1634 seconds with return value 0
Pressione qualquer tecla para continuar. . .
And here is the code called with the parameters:
csock -listen 2020
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <winsock2.h>
void delay(int milisecond);
char* LastErrorDescription();
/*****************************************************************************************
EXEMPLO DE PARAMETRO:
csock -h IP_v_4_Address -p Remote_Port -t 500
csock -listen 2020
******************************************************************************************/
/**************************************************
PENDENCIAS:
- IMPLEMENTAR IPv6
- IMPLEMENTAR MODO SERVIDOR
- REFAZER PARAMETROS PACKAGE (-pack)
***************************************************/
int main(int argc, char *argv[]) {
struct sockaddr_in sckAddr, adrIncomming;
char request[512] = ""; //= "GET http://www.brasil.gov.br HTTP/1.1\r\n\r\n"; //"GET /index.html HTTP/1.1\nHost: www.brasil.gov.br\n";
char BufferIn[10240];
WSADATA wsaDADOS;
int retWSA;
int retCon;
int retSend;
int retRecv;
int retBind;
int i;
int imsg;
int time_limit = 1000; // milisegundos aguardando recebimento de pacotes
clock_t registrador_tempo;
_Bool closed_connection = 0;
_Bool serverMode = 0;
_Bool nonpersist = 0;
_Bool bIPv6 = 0;
SOCKET wsocket;
SOCKET wserver;
WORD sckVersion = (2) << 8 | (2); // sckVersion 2.2 -> 0000001000000010
//printf("Quantidade de Parametros: %i", argc);
for(i = 0; i < argc; i ++){
if(!strcmp(argv[i], "-h")){
printf("\n:: HOST: %s", argv[i + 1]);
sckAddr.sin_addr.s_addr = inet_addr(argv[i + 1]);
}
if(!strcmp(argv[i], "-p")){
printf("\n:: PORT: %s", argv[i + 1]);
sckAddr.sin_port = htons(atoi(argv[i + 1]));
}
if(!strcmp(argv[i], "-t")){
time_limit = atoi(argv[i + 1]);
}
//COMANDOS MODO SERVIDOR
else if(!strcmp(argv[i], "-listen")){
serverMode = 1;
printf("\n:: SERVER MODE");
sckAddr.sin_addr.s_addr = htonl(INADDR_ANY);
sckAddr.sin_port = htons(atoi(argv[i + 1]));
printf("\n:: PORT: %s", argv[i + 1]);
}
}
printf("\n:: Time Limit receiving: %ims", time_limit);
// TRABALHO COM ENDEREÇO
sckAddr.sin_family = AF_INET; //23 == AF_INET6 para usar IPv6
//sckAddr.sin_port = htons(80);
//sckAddr.sin_addr.s_addr = inet_addr("170.246.252.243");
//Inicialização WSA Socket Application
printf("\n\n:: WSA Version: ");
retWSA = WSAStartup(sckVersion, &wsaDADOS);
if (retWSA == 0) {
printf("%04X", wsaDADOS.wVersion);
//Cria o SOCKET
printf("\n:: Criando SOCKET: ");
if(serverMode){
wserver = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(wserver > 0){
printf("OK");
retBind = bind(wserver, (struct sockaddr*)&sckAddr, sizeof(sckAddr));
printf("\n:: SOCKET Binding: ");
if (retBind == 0)
printf("OK");
else
printf("ERRO %i [%s]", WSAGetLastError(), LastErrorDescription());
}
else
printf("ERRO %i [%s]", WSAGetLastError(), LastErrorDescription());
}
else { //CLIENT MODE
wsocket = socket(bIPv6 ? 23 : AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(wsocket > 0)
printf("OK");
else
printf("ERRO %i [%s]", WSAGetLastError(), LastErrorDescription());
}
//MODO SERVIDOR
if(serverMode){
printf("\n\n:: LISTENING . . .\n");
listen(wserver, 2);
//do {
wsocket = accept(wserver, (struct sockaddr*)&adrIncomming, (int*)sizeof(adrIncomming));
printf("WSA Error: %s\nSocket Value: %i\n\n", LastErrorDescription(), wsocket); //TO DEPURATE
//} while(wsocket == SOCKET_ERROR);
closesocket(wserver);
if(wsocket != SOCKET_ERROR){
printf("\n:: Conexao estabelecida com: %s", inet_ntoa(adrIncomming.sin_addr)); //Tentar obter ENDEREÇO REMOTO com getpeername
retCon = 0;
}
else
retCon = -1;
}
//MODO CLIENTE
else{
//Conecta
printf("\n:: Conectando: ");
retCon = connect(wsocket, (struct sockaddr *)&sckAddr, sizeof(sckAddr));
if(retCon == 0)
printf("OK");
else
printf("ERRO %i [%s]", WSAGetLastError(), LastErrorDescription());
}
//CONEXAO ESTABELECIDA
if (retCon == 0) {
// ENVIA E RECEBE
while(strcmp(&request[0], "exIt")){
//ENVIA PACOTE
if (!nonpersist){
printf("\n\n:: ENVIAR>");
for(i=0;i<sizeof(request);i++)
request[i] = '\0';
fgets(&request, sizeof(request), stdin);
// Trata os PACOTES a serem ENVIADOS
for (i = 0; i < sizeof(request); i++){
if(request[i] == '\0'){
// Finaliza STRING 1 posicao antes ELIMINANDO Lf do fgets()
for(imsg = i - 1; imsg < sizeof(request); imsg++)
request[imsg] = '\0';
break;
}
// \n
else if (request[i] == '\\' && request[i + 1] == 'n'){
request[i] = '\n';
// Traz todos os caracteres para 1 posicao antes
for (imsg = i + 1; imsg < sizeof(request); imsg++)
request[imsg] = request[imsg + 1];
}
// \r
else if (request[i] == '\\' && request[i + 1] == 'r'){
request[i] = '\r';
// Traz todos os caracteres para 1 posicao antes
for (imsg = i + 1; imsg < sizeof(request); imsg++)
request[imsg] = request[imsg + 1];
}
}
}
//Depuracao: checar string de pacotes e ASCII da string de pacotes
/*
printf("\n\n%s.", &request);
printf("\n\n.");
for(i=0;i<sizeof(request);i++)
printf("%i ", request[i]);
printf(".");
*/
//Envia pacotes
if(strcmp(&request, "exIt")){
printf("\n:: Enviando pacotes: ");
if(send(wsocket, request, sizeof(request), 0) == SOCKET_ERROR){ // Erro no ENVIO
printf("ERRO %i [%s]", WSAGetLastError(), LastErrorDescription());
}
else //PACOTES ENVIADOS COM EXITO
printf("OK");
delay(time_limit);
//RECEBE PACOTE
retRecv = recv(wsocket, BufferIn, sizeof(BufferIn), 0);
if (retRecv == 0) {
printf("\n\n:: %s", LastErrorDescription());
break;
}
else {
printf("\n\n:: RECEBIDO:\n");
printf("%s", BufferIn);
}
}
//Finaliza se for conexao nao persistente
if(nonpersist)
strcpy(&request, "exIt");
}
}
else { //Erro na CONEXÃO
printf("ERRO %i [%s]", WSAGetLastError(), LastErrorDescription());
}
//Fecha o SOCKET
closesocket(wsocket);
}
else { // Erro no WSAStartup
printf("ERRO %i [%s]", WSAGetLastError(), LastErrorDescription());
}
// Finaliza Utilização do SOCKET
WSACleanup();
return 0;
}
void delay(int milisecond){
clock_t registra_tempo = clock();
while(clock() < registra_tempo + milisecond)
;
}
char* LastErrorDescription(){
static char* ret;
switch(WSAGetLastError()){
case WSAEINTR:{
ret = "Interrupted function call";
break;
}
case WSAEBADF:{
ret = "WSAEBADF";
break;
}
case WSAEACCES:{
ret = "WSAEACCES";
break;
}
case WSAEFAULT:{
ret = "Bad address";
break;
}
case WSAEINVAL:{
ret = "Invalid argument";
break;
}
case WSAEMFILE:{
ret = "Too many open files";
break;
}
case WSAEWOULDBLOCK:{
ret = "Operation would block";
break;
}
case WSAEINPROGRESS:{
ret = "Operation now in progress";
break;
}
case WSAEALREADY:{
ret = "Operation already in progress";
break;
}
case WSAENOTSOCK:{
ret = "Socket operation on non-socket";
break;
}
case WSAEDESTADDRREQ:{
ret = "Destination address required";
break;
}
case WSAEMSGSIZE:{
ret = "Message too long";
break;
}
case WSAEPROTOTYPE:{
ret = "Protocol wrong type for socket";
break;
}
case WSAENOPROTOOPT:{
ret = "Bad protocol option";
break;
}
case WSAEPROTONOSUPPORT:{
ret = "Protocol not supported";
break;
}
case WSAESOCKTNOSUPPORT:{
ret = "Socket type not supported";
break;
}
case WSAEOPNOTSUPP:{
ret = "Operation not supported";
break;
}
case WSAEPFNOSUPPORT:{
ret = "Protocol family not supported";
break;
}
case WSAEAFNOSUPPORT:{
ret = "Address family not supported by protocol family";
break;
}
case WSAEADDRINUSE:{
ret = "Address already in use";
break;
}
case WSAEADDRNOTAVAIL:{
ret = "Cannot assign requested address";
break;
}
case WSAENETDOWN:{
ret = "Network is down";
break;
}
case WSAENETUNREACH:{
ret = "Network is unreachable";
break;
}
case WSAENETRESET:{
ret = "Network dropped connection on reset";
break;
}
case WSAECONNABORTED:{
ret = "Software caused connection abort";
break;
}
case WSAECONNRESET:{
ret = "Connection reset by peer";
break;
}
case WSAENOBUFS:{
ret = "No buffer space available";
break;
}
case WSAEISCONN:{
ret = "Socket is already connected";
break;
}
case WSAENOTCONN:{
ret = "Socket is not connected";
break;
}
case WSAESHUTDOWN:{
ret = "Cannot send after socket shutdown";
break;
}
case WSAETOOMANYREFS:{
ret = "WSAETOOMANYREFS";
break;
}
case WSAETIMEDOUT:{
ret = "Connection timed out";
break;
}
case WSAECONNREFUSED:{
ret = "Connection refused";
break;
}
case WSAELOOP:{
ret = "WSAELOOP";
break;
}
case WSAENAMETOOLONG:{
ret = "WSAENAMETOOLONG";
break;
}
case WSAEHOSTDOWN:{
ret = "Host is down";
break;
}
case WSAEHOSTUNREACH:{
ret = "No route to host";
break;
}
case WSAENOTEMPTY:{
ret = "WSAENOTEMPTY";
break;
}
case WSAEPROCLIM:{
ret = "Too many processes";
break;
}
case WSAEUSERS:{
ret = "WSAEUSERS";
break;
}
case WSAEDQUOT:{
ret = "WSAEDQUOT";
break;
}
case WSAESTALE:{
ret = "WSAESTALE";
break;
}
case WSAEREMOTE:{
ret = "WSAEREMOTE";
break;
}
case WSASYSNOTREADY:{
ret = "Network subsystem is unavailable";
break;
}
case WSAVERNOTSUPPORTED:{
ret = "WINSOCK.DLL version out of range";
break;
}
case WSANOTINITIALISED:{
ret = "Successful WSAStartup() not yet performed";
break;
}
case WSAEDISCON:{
ret = "WSAEDISCON";
break;
}
case WSAENOMORE:{
ret = "WSAENOMORE";
break;
}
case WSAECANCELLED:{
ret = "WSAECANCELLED";
break;
}
case WSAEINVALIDPROCTABLE:{
ret = "WSAEINVALIDPROCTABLE";
break;
}
case WSAEINVALIDPROVIDER:{
ret = "WSAEINVALIDPROVIDER";
break;
}
case WSAEPROVIDERFAILEDINIT:{
ret = "WSAEPROVIDERFAILEDINIT";
break;
}
case WSASYSCALLFAILURE:{
ret = "WSASYSCALLFAILURE";
break;
}
case WSASERVICE_NOT_FOUND:{
ret = "WSASERVICE_NOT_FOUND";
break;
}
case WSATYPE_NOT_FOUND:{
ret = "WSATYPE_NOT_FOUND";
break;
}
case WSA_E_NO_MORE:{
ret = "WSA_E_NO_MORE";
break;
}
case WSA_E_CANCELLED:{
ret = "WSA_E_CANCELLED";
break;
}
case WSAEREFUSED:{
ret = "WSAEREFUSED";
break;
}
case WSAHOST_NOT_FOUND:{
ret = "Host not found";
break;
}
case WSATRY_AGAIN:{
ret = "Non-authoritative host not found";
break;
}
case WSANO_RECOVERY:{
ret = "This is a non-recoverable error";
break;
}
case WSANO_DATA:{
ret = "Valid name, no data record of requested type";
break;
}
}
return ret;
}

The function accept third parameter addrlen is a pointer. It must point to a valid memory location. Additionally it's an in/out pointer, i.e. a variable. So you must create a variable with a value the is the size of your adrIncomming variable. After return from accept the variable will have the actual length of the address.
This code is more appropriate.
int adrLength = sizeof(adrIncomming);
wsocket = accept(wserver, (struct sockaddr*)&adrIncomming, &adrLength);
Edit: The link in this answer and the example is specific for the WinSock API since the question is tagged with Windows. Other implementations of a socket API might have different function signatures.

Related

My socket game have some problems, and i can't understand why

The code now works fine, but I have some question to ask to you.
The first one is, why received messages are slow (about 1 second)? (not in local)
The second one is, why do I need Sleep function at line 213?
The third one is, why do I need a a confirmation from recv in receiveMessage void, for receive all messages?
On linux socket all is fine.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <WS2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
#define MAXSIZE 1024
#define PORT 13333
#define FINISH_GAME "cmdfinishgame"
#define RESET_GAME "cmdresetgame"
#define CLOSE_SOCKET "cmdclosesocket"
#define CLEAR_CONSOLE "cmdclearconsole"
const char trustedLetters[27] = "abcdefghijklmnopqrstuvwxyz";
SOCKET serverSocket;
SOCKET clientSocket;
char buffer[MAXSIZE];
char usedLetters[27] = "";
int choose;
void setupServer();
void setupClient();
void sendMessage(char * message);
void receiveMessage(char * message);
int setupGameForServer();
int setupGameForClient();
void startGame();
void spectGame();
void getAUXofStr(char * _Src, char * _Dest);
void spaceString(char * _Src, char * _Dest);
void getChar(char *c);
void waitForUserInput();
void replace(char * _Str, char _Which, char _With);
main.c:
#include "main.h"
int main()
{
while (1)
{
system("cls");
printf("----------------------- \n");
printf("[1] Crea una stanza \n");
printf("[2] Entra in una stanza \n");
printf("----------------------- \n\n");
printf("Scelta: ");
scanf("%s", buffer);
printf("\n");
choose = atoi(buffer);
if (choose == 1)
{
//Inizializzo lato server
setupServer();
//Aspetto che qualcuno si connetta
SOCKADDR_IN clientInfo;
int clientSize = sizeof(clientInfo);
clientSocket = accept(serverSocket, (LPSOCKADDR)&clientInfo, &clientSize);
if (clientSocket == INVALID_SOCKET)
{
exit(1);
}
closesocket(serverSocket);
//in
while (setupGameForServer() == 0);
break;
}
else if (choose == 2)
{
//Inizializzo lato client
setupClient();
while (setupGameForClient() == 0);
break;
}
else if (choose == 99)
{
break;
}
}
closesocket(clientSocket);
WSACleanup();
return 0;
}
int setupGameForServer()
{
memset(usedLetters, 0, sizeof(usedLetters));
memset(buffer, 0, sizeof(buffer));
//Inizia nuova partita
while (1)
{
system("cls");
printf("---------------------------- \n");
printf("[1] Inizia nuova partita \n");
printf("[2] Chiudi \n");
printf("---------------------------- \n\n");
printf("Scelta: ");
scanf("%s", buffer);
printf("\n");
choose = atoi(buffer);
if (choose == 1)
{
sendMessage(RESET_GAME);
break;
}
else if (choose == 2)
{
sendMessage(CLOSE_SOCKET);
return 1;
}
else
{
printf("Errore! Inserire un opzione valida! \n\n\n");
waitForUserInput();
}
}
//-------------
//Chi indovina?
while (1)
{
system("cls");
printf("---------------------- \n");
printf("[1] Indovina il server \n");
printf("[2] Indovina il client \n");
printf("---------------------- \n\n");
printf("Scelta: ");
scanf("%s", buffer);
printf("\n");
choose = atoi(buffer);
if (choose == 1)
{
sendMessage("1");
startGame();
}
else if (choose == 2)
{
sendMessage("2");
printf("Inserisci la frase: ");
scanf(" %[^\n]", buffer);
printf("\n");
sendMessage(buffer);
spectGame();
}
else
{
printf("Errore! Inserire un opzione valida! \n\n\n");
waitForUserInput();
continue;
}
break;
}
//-------------
return 0;
}
int setupGameForClient()
{
//
receiveMessage(buffer);
if (strcmp(buffer, RESET_GAME) == 0)
{
memset(usedLetters, 0, sizeof(usedLetters));
memset(buffer, 0, sizeof(buffer));
}
else if (strcmp(buffer, CLOSE_SOCKET) == 0)
{
return 1;
}
Sleep(10);
//printf("OK!"); //wtf?
//
receiveMessage(buffer);
int i = atoi(buffer);
if (i == 1)
{
printf("Inserisci la frase: ");
scanf(" %[^\n]", buffer);
printf("\n");
sendMessage(buffer);
spectGame();
}
else if (i == 2)
{
startGame();
}
return 0;
}
void setupServer()
{
//Inizializzazione winsock
WSADATA wsaData;
WORD version = MAKEWORD(2, 2);
if (WSAStartup(version, &wsaData))
{
exit(1);
}
//Creazione socket
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET)
{
exit(1);
}
//Bind dell'ip e della porta
SOCKADDR_IN serverInfo;
serverInfo.sin_family = AF_INET;
serverInfo.sin_addr.s_addr = ADDR_ANY;
serverInfo.sin_port = htons(PORT);
bind(serverSocket, (LPSOCKADDR)&serverInfo, sizeof(serverInfo));
//Messa del socket in ascolto
listen(serverSocket, 1);
}
void setupClient()
{
//Inizializzazione winsock
WSADATA wsaData;
WORD version = MAKEWORD(2, 2);
if (WSAStartup(version, &wsaData))
{
exit(1);
}
//Creazione socket
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket == INVALID_SOCKET)
{
exit(1);
}
//ip
char ip[16];
printf("Inserisci ip: ");
scanf("%s", ip);
printf("\n");
//Mi connetto al server
SOCKADDR_IN clientInfo;
clientInfo.sin_family = AF_INET;
clientInfo.sin_addr.s_addr = inet_addr(ip);
clientInfo.sin_port = htons(PORT);
connect(clientSocket, (LPSOCKADDR)&clientInfo, sizeof(clientInfo));
}
void startGame()
{
receiveMessage(buffer);
char *phrase;
char *phraseAUX;
phrase = (char *)malloc(strlen(buffer) * sizeof(char));
phraseAUX = (char *)malloc(strlen(buffer) * sizeof(char));
memcpy(phrase, buffer, strlen(buffer));
phrase[strlen(buffer)] = '\0';
phraseAUX[strlen(buffer)] = '\0';
getAUXofStr(phrase, phraseAUX);
system("cls");
sendMessage(CLEAR_CONSOLE);
char c;
int flag = 0;
int lives = 5;
while (1)
{
//stampo lo status
spaceString(phraseAUX, buffer);
printf(buffer);
printf("\n");
sendMessage(buffer);
sendMessage("\n");
snprintf(buffer, 10, "%d", lives);
printf("Vite rimaste: ");
printf(buffer);
printf("\n");
sendMessage("Vite rimaste: ");
sendMessage(buffer);
sendMessage("\n");
//Vedo se ho vinto
if (strcmp(phrase, phraseAUX) == 0)
{
printf("Hai vinto! \n");
sendMessage("Hai scelto una parola troppo easy colione! \n");
break;
}
//Vedo se ho perso
if (lives <= 0)
{
printf("Hai perso! La parola era: \"%s\"\n", phrase);
sendMessage("Il tuo amico finocchio ha perso! GGEZ! \n");
break;
}
//Inserimento carattere
printf("Inserisci carattere: ");
getChar(&c);
printf("\n");
system("cls");
sendMessage(CLEAR_CONSOLE);
//Vedo se la lettera è valida
flag = 0;
for (int i = 0; i < strlen(usedLetters); i++)
{
if (tolower(c) == usedLetters[i])
{
printf("Lettera già utilizzata! \n");
sendMessage("Il tuo amico non capisce un cazzo, ha riinserito la stessa lettera! \n");
flag = 1;
break;
}
}
if (flag)
continue;
else
strncat(usedLetters, &c, 1);
//Sostituisco la lettera nella stringa ausiliaria
flag = 0;
for (int i = 0; i < strlen(phrase); i++)
{
if (tolower(c) == tolower(phrase[i]))
{
phraseAUX[i] = phrase[i];
flag = 1;
}
}
if (!flag)
lives -= 1;
}
waitForUserInput();
sendMessage(FINISH_GAME);
printf("\n\n");
}
void spectGame()
{
while (1)
{
receiveMessage(buffer);
if (strcmp(buffer, CLEAR_CONSOLE) == 0)
{
system("cls");
}
else if (strcmp(buffer, FINISH_GAME) == 0)
{
break;
}
else
{
printf("%s", buffer);
}
}
}
void receiveMessage(char *message)
{
int result;
memset(message, 0, sizeof(message));
//u_long mode = 1; // 1 to enable non-blocking socket
//ioctlsocket(clientSocket, FIONREAD, &mode);
result = recv(clientSocket, message, MAXSIZE, 0);
if (result == 0)
{
exit(1);
}
send(clientSocket, "1", 2, 0);
}
void sendMessage(char *message)
{
int result;
char localBuffer[2];
//u_long mode = 1; // 1 to enable non-blocking socket
//ioctlsocket(clientSocket, FIONBIO, &mode);
result = send(clientSocket, message, (int)strlen(message) + 1, 0);
if (result == 0)
{
exit(1);
}
recv(clientSocket, localBuffer, 2, 0);
if (strcmp(localBuffer, "1") != 0) {
waitForUserInput();
exit(1);
}
}
void getChar(char *c)
{
char str[MAXSIZE];
scanf("%s", str);
*c = str[0];
}
void getAUXofStr(char *_Src, char *_Dest)
{
char trustedLetters[] = "abcdefghijklmnopqrstuvwxyz";
int flag = 0;
for (int s1 = 0; s1 < strlen(_Src); s1 += 1)
{
flag = 0;
for (int s2 = 0; s2 < strlen(trustedLetters); s2 += 1)
{
if (tolower(_Src[s1]) == trustedLetters[s2])
{
_Dest[s1] = '_';
flag = 1;
break;
}
}
if (!flag)
_Dest[s1] = _Src[s1];
}
}
void spaceString(char *_Src, char *_Dest)
{
char finalstr[MAXSIZE];
char space = ' ';
ZeroMemory(finalstr, sizeof(finalstr));
for (int s1 = 0; s1 < strlen(_Src); s1 += 1)
{
strncat(finalstr, &_Src[s1], 1);
strncat(finalstr, &space, 1);
}
strcpy(_Dest, finalstr);
}
void waitForUserInput()
{
printf("Premere un tasto per continuare...\n");
fflush(stdin);
getchar();
}

SSL_connect from a client while the server is in SSL_read

I have a non-blocking socket and using select to handle connections from multiple SSL clients :
I have tried suggestions regarding handling SSL_ERROR_WANT_READ, like repeat SSL_read call, or return back to Select, but it seems to be not working in my case.
while (1)
{
start:
if (readyCount = select(FD_SETSIZE, &read_fd_set, NULL, NULL, &timeout) < 0)
{
exit(EXIT_FAILURE);
}
for (int i = 0; i < FD_SETSIZE; ++i)
if (FD_ISSET(i, &read_fd_set))
{
if (i == sockfd)
{
newSocket = accept(sockfd, (struct sockaddr *) &clientname, (socklen_t*)&size);
}
else
{
ssl = SSL_new(ctx);
SSL_set_fd(ssl, i);
accept:
int err = SSL_accept(ssl);
if (0 >= err)
{ // it never goes here
int resultCode = SSL_get_error(ssl, err);
switch (resultCode)
{
case SSL_ERROR_NONE:
goto accept;
break;
case SSL_ERROR_ZERO_RETURN:
SSL_shutdown(ssl);
break;
case SSL_ERROR_SYSCALL:
break;
case SSL_ERROR_WANT_READ:
break;
case SSL_ERROR_WANT_WRITE:
break;
case SSL_ERROR_WANT_CONNECT:
break;
case SSL_ERROR_WANT_ACCEPT:
goto accept;
break;
case SSL_ERROR_WANT_X509_LOOKUP:
break;
case SSL_ERROR_SSL:
break; }
default:
break;
}
}
else
{
Call_Read(...)
}
SSL_free(ssl);
close(i);
FD_CLR(i, &active_fd_set);
}
}
}
Call_Read(...)
{
int fd = SSL_get_fd(ssl);
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
while (data_size > 0)
{
bytes_recv = SSL_read(ssl, data, data_size);
if (bytes_recv <= 0)
{
if (SSL_ERROR_WANT_READ == SSL_get_error(ssl, bytes_recv))
{
testtt = SSL_pending(ssl); //always 0
/*SSL_renegotiate(ssl);
SSL_do_handshake(ssl);*/
continue;
}
if (SSL_ERROR_WANT_WRITE == SSL_get_error(ssl, bytes_recv))
{
testtt = SSL_pending(ssl);
int blocked_on_SSL_ERROR_WANT_WRITE = 1;
continue; }
}
return bytes_recv;
}
data += bytes_recv;
data_size -= bytes_recv;
}
return 1;
}
Client Write:
{
while (data_size > 0)
{
bytes_sent = SSL_write(ssl, data_ptr, data_size);
if (errno == EPIPE) == doesn’t reach this line, debugger stops with EPIPE
{
printf("WRITE socket returned EPIPE”);
return -1;
}
if (bytes_sent < 0)
{
int err = SSL_get_error(ssl, bytes_sent);
switch (err)
{
case SSL_ERROR_WANT_READ:
printf(" SSL_ERROR_WANT_READ\n");
case SSL_ERROR_WANT_WRITE:
printf(" SSL_ERROR_WANT_WRITE\n");
default:
;
}
}
data_ptr += bytes_sent;
data_size -= bytes_sent;
}
return 1;
}
I don’t know how to handle the situation, when the server is in SSL_Read and some of clients calls SSL_Connect.
In such a scenario, the Call_Read will be in infinite loop for SSL_ERROR_WANT_READ. If I replace the “continue” statement with a flag that will finish the loop and the caller returns back to Select the client will break with broken pipe error, and it even doesn’t reach the line “WRITE socket returned EPIPE”. The same will happen if I return from the read loop back to Accept, instead of to Select.
I am missing here something and I am wondering if I should do some changes to the client also.
Any suggestions?

Client-server echo-chat (multiplexing I/O + threads)

I just started learning C language and I'm trying to get deal with Windows Sockets.
The problem is the server can accept and send message only once.
I used debug mode and saw that work stops in select() from the server part. It seems fine in client (but I'm not sure) and don't see the problem in my code. But I have such a result. What's wrong?
I noticed that my tv.tv_sec isn't defined and I did that just before select, nothing was changed.
And just to be sure: as I need to receive and send message, I don't need write descriptor in accept(), right?
Client uses CreateThread function where I try to send message. Send is in while(1) cycle in main()
Server part:
int main(int argc, char* argv[])
{
/* definitions, WSAStartup(), socket(), bind(), listen()
Listening socket is a returned value of listen() function*/
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
while (1)
{
// SELECT (LISTENING SOCKET)
FD_ZERO(&readSet);
FD_SET(listeningSocket, &readSet);
tv.tv_sec = 5;
printf("Listening: Read FD: %d; Write FD : %d;\n", FD_ISSET(listeningSocket, &readSet), FD_ISSET(listeningSocket, &writeSet));
if ((retVal = select(listeningSocket + 1, &readSet, NULL, NULL, 0)) == SOCKET_ERROR)
{
printf("Select error ");
break;
}
else if (retVal == 0)
{
printf(". . .\n");
continue;
}
else
{
// READ SD
if ((FD_ISSET(listeningSocket, &readSet)) != SOCKET_ERROR)
{
if ((newSocketDescriptor = accept(listeningSocket, (struct sockaddr *)&clientAddr, &clientAddrSize)) == SOCKET_ERROR)
{
printf("Accept error ");
break;
}
FD_ZERO(&readSet);
FD_SET(newSocketDescriptor, &readSet);
HOSTENT *hst = gethostbyaddr((const char *)&serverAddr.sin_addr.s_addr, 4, AF_INET);
printf("Welcome %s (%s:%d) new connected\n", hst->h_name, inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
printf("Read FD: %d; Write FD : %d;\n", FD_ISSET(newSocketDescriptor, &readSet), FD_ISSET(newSocketDescriptor, &writeSet));
// READ
if (FD_ISSET(newSocketDescriptor, &readSet) != 0)
{
if ((numBytes = recv(newSocketDescriptor, &bufferData[0], sizeof(bufferData), 0)) == SOCKET_ERROR)
{
printf("Recv failed \n");
freeSocketInformation(newSocketDescriptor);
break;
}
bufferData[numBytes] = '\0';
printf("Client -> Server: %s\n", &bufferData[0]);
}
// WRITE
FD_ZERO(&writeSet);
FD_SET(newSocketDescriptor, &writeSet);
printf("Read FD: %d; Write FD : %d;\n", FD_ISSET(newSocketDescriptor, &readSet), FD_ISSET(newSocketDescriptor, &writeSet));
if (FD_ISSET(newSocketDescriptor, &writeSet) != 0)
{
//fgets(&bufferData[0], sizeof(bufferData), stdin);
if (send(newSocketDescriptor, &bufferData[0], strlen(&bufferData[0]), 0) == SOCKET_ERROR)
{
printf("Send error ");
freeSocketInformation(newSocketDescriptor);
break;
}
bufferData[numBytes] = '\0';
printf("Server -> Client: %s\n", &bufferData[0]);
}
printf("Read FD: %d; Write FD : %d;\n", FD_ISSET(newSocketDescriptor, &readSet), FD_ISSET(newSocketDescriptor, &writeSet));
FD_SET(newSocketDescriptor, &readSet);
}
}
}
//FD_CLR(listeningSocket, &readSet);
closesocket(newSocketDescriptor);
} while (FALSE);
printf("- Error code: %d\n", WSAGetLastError());
closesocket(listeningSocket);
WSACleanup();
return 0;
}
Client part (it uses CreateThread function which is in the end of the code):
/* definitions, socket(), connect()*/
if (ioctlsocket(socketDescriptor, FIONBIO, (unsigned long *)&nb) != 0)
{
printf("ioctlsocket error ");
break;
}
FD_ZERO(&writeSet);
FD_SET(socketDescriptor, &writeSet);
if ((retVal = select(socketDescriptor + 1, NULL, &writeSet, NULL, &tv)) == SOCKET_ERROR)
{
printf("Send non-blocking error ");
break;
}
else if (retVal == 0)
{
printf("Non-blocking connect time limit is expired");
break;
}
}
printf("Connection with %s\n", SERVERADDR);
DWORD thID;
printf("Socket Desciptor: %d\n", socketDescriptor);
HANDLE hThread = CreateThread(NULL, NULL, HandleReadThread, (LPVOID)socketDescriptor, NULL, &thID);
printf("Thread ID: %d\n", thID);
while (1)
{
// WRITE
printf("Client -> Server: ");
fgets(&bufferData[0], sizeof(bufferData), stdin);
FD_ZERO(&writeSet);
FD_SET(socketDescriptor, &writeSet);
tv.tv_sec = 5;
if ((retVal = select(socketDescriptor + 1, NULL, &writeSet, NULL, &tv)) == SOCKET_ERROR)
{
printf("Send non-blocking error ");
break;
}
if (FD_ISSET(socketDescriptor, &writeSet) != 0)
{
if (send(socketDescriptor, bufferData, strlen(&bufferData[0]), 0) == SOCKET_ERROR)
{
printf("Send error ");
break;
}
}
}
} while (FALSE);
printf("- Error code: %d\n", WSAGetLastError());
closesocket(socketDescriptor);
WSACleanup();
return 0;
}
DWORD WINAPI HandleReadThread(LPVOID serverSocket)
{
SOCKET socketDescriptor;
socketDescriptor = (SOCKET)serverSocket;
char bufferData[MAXDATASIZE] = { 0 };
int retVal;
fd_set readSet;
timeval tv = { 0 };
tv.tv_sec = 5;
int numBytes;
int nclients = 0;
while (1)
{
FD_ZERO(&readSet);
FD_SET(socketDescriptor, &readSet);
if ((retVal = select(socketDescriptor + 1, &readSet, NULL, NULL, &tv)) == SOCKET_ERROR)
{
printf("Select error. Error code: %d", WSAGetLastError());
break;
}
else if (retVal == 0)
{
//printf(". . .\n");
continue;
}
else
{
//FD_ZERO(socketDescriptor, &readSet);
//FD_SET(socketDescriptor, &readSet);
// READ
if (FD_ISSET(socketDescriptor, &readSet) != 0)
{
if ((numBytes = recv(socketDescriptor, &bufferData[0], sizeof(bufferData), 0)) == SOCKET_ERROR)
{
printf("Recv error in Thread. Error code: %d\n", WSAGetLastError());
break;
}
printf("\nSocket Desciptor: %d\n", socketDescriptor);
bufferData[numBytes] = '\0';
printf("Server -> Client: %s\n", &bufferData[0]);
}
}
}
closesocket(socketDescriptor);
return 0;
}
Well, I solved it by myself. The condition
if ((FD_ISSET(listeningSocket, &readSet)) != 0)
worked for all while(1) cycle, it should has been finished after accept() function.
Also I added these lines in the beginning of while(1) after FD_SET for readSet:
if (newSocketDescriptor)
{
FD_SET(newSocketDescriptor, &readSet);
}
The chat started working but there are a lot of stuffs to work at :)

How to handle 3 way send() and recv() in BSD socket using C

After sending "wrong" username - client won't start loop from beginning, actually, there is no server asks:?
Dunno how to handle 3 way client-server message sender for such auth. I must understand this to continue such message receiving in further.
client.c:
int is_authenticated = 0;
size_t sendline_s;
while (!is_authenticated) {
recv(sockfd, recvline, MAXLINE, 0);
printf("%s", "server asks:");
fputs(recvline, stdout);
printf("?> ");
fflush(stdout);
while (fgets(sendline, MAXLINE, stdin) != NULL) {
sendline_s = strlen(sendline);
if (sendline[sendline_s-1] == '\n') {
sendline[sendline_s-1] = '\0';
send(sockfd, sendline, sendline_s+1, 0);
puts("username sended");
break;
}
// handling ^Z (EOF) here
//
}
recv(sockfd, recvline, MAXLINE, 0);
printf("\nawaiting for server ACK\n");
puts(recvline);
if (strcmp(recvline, "ACCEPTED_AUTH") == 0) {
puts("authentication complete successful");
is_authenticated = 1;
}
else {
puts("authentication declined");
}
}
server.c
int is_authenticated = 0;
char *accepted = "ACCEPTED_AUTH";
char *name = "kaldown";
char *wrong = "wrong";
size_t name_s = strlen(name);
size_t accepted_s = strlen(accepted);
size_t wrong_s = strlen(wrong);
while (!is_authenticated) {
send(connfd, name, name_s+1, 0);
puts("authentication request was send");
recv(connfd, buf, MAXLINE, 0);
printf("username was recieved: ");
puts(buf);
if (strcmp(buf, name) == 0) {
puts("hurray");
send(connfd, accepted, accepted_s+1, 0);
is_authenticated = 1;
//break;
}
else {
puts("WRONG NAME");
send(connfd, wrong, wrong_s+1, 0);
}
}
But, If i send right username - it passes the block and everything goes well.
server:
while (!is_authenticated) {
if ((n = recv(connfd, buf, MAXLINE-1,0))== -1) {
perror("recv");
exit(1);
}
else if (n == 0) {
printf("Connection closed\n");
//So I can now wait for another client
break;
}
printf("\n%d truely recieved", n);
buf[n] = '\0';
printf("Server:Msg Received %s\n", buf);
if (strcmp(buf, "DONE") == 0) {
strcpy(buf, "DONE");
if ((send(connfd,buf, strlen(buf),0))== -1)
{
fprintf(stderr, "Failure Sending Message\n");
close(connfd);
break;
}
puts("KONEC");
is_authenticated = 1;
}
else {
if ((send(connfd,buf, strlen(buf),0))== -1)
{
fprintf(stderr, "Failure Sending Message\n");
close(connfd);
break;
}
}
printf("Server:Msg being sent: %s\nNumber of bytes sent: %d\n", buf, strlen(buf));
}
client:
while (!is_authenticated) {
printf("Client: Enter Data for Server:\n");
if (fgets(sendline, MAXLINE-1, stdin) != NULL) {
if (sendline[(strlen(sendline)-1)] == '\n') {
sendline[strlen(sendline)-1] = '\0';
if ((send(sockfd,sendline, strlen(sendline),0))== -1) {
fprintf(stderr, "Failure Sending Message\n");
close(sockfd);
exit(1);
}
else {
printf("Client:Message being sent: %s\n",sendline);
n = recv(sockfd, sendline, sizeof(sendline),0);
if ( n <= 0 )
{
printf("Either Connection Closed or Error\n");
//Break from the While
break;
}
sendline[n] = '\0';
if (strcmp(sendline, "DONE") == 0) {
puts("AUTH PASSED");
is_authenticated = 1;
}
printf("Client:Message Received From Server - %s\n",sendline);
}
}
//EOF
}
}

How to set l2tp preshared key?

I need to create RASENTRY for L2TP with pre-shared key set. So far, I can see that entry has somewhat correct flags, but no key is set, unfortunately.
Here is code:
int common_ras_manager_create_entry(const char* server_address, const char* username, const char* password, MY_VPN_CONNECTION_TYPE connection_type, const char* preshared_key)
{
DWORD EntryInfoSize = 0;
DWORD DeviceInfoSize = 0;
DWORD Ret;
LPRASENTRY lpRasEntry;
LPBYTE lpDeviceInfo;
// Get buffer sizing information for a default phonebook entry
if ((Ret = RasGetEntryProperties(NULL, "", NULL, &EntryInfoSize, lpDeviceInfo, &DeviceInfoSize)) != 0)
{
if (Ret != ERROR_BUFFER_TOO_SMALL)
{
printf("RasGetEntryProperties sizing failed with error %d\n", Ret);
return Ret;
}
}
lpRasEntry = (LPRASENTRY) GlobalAlloc(GPTR, EntryInfoSize);
if (DeviceInfoSize == 0)
lpDeviceInfo = NULL;
else
lpDeviceInfo = (LPBYTE) GlobalAlloc(GPTR, DeviceInfoSize);
// Get default phonebook entry
lpRasEntry->dwSize = sizeof(RASENTRY);
if ((Ret = RasGetEntryProperties(NULL, "", lpRasEntry, &EntryInfoSize, lpDeviceInfo, &DeviceInfoSize)) != 0)
{
printf("RasGetEntryProperties failed with error %d\n", Ret);
return Ret;
}
// Validate new phonebook name "Testentry"
if ((Ret = RasValidateEntryName(NULL, APP_NAME)) != ERROR_SUCCESS)
{
printf("RasValidateEntryName failed with error %d\n", Ret);
if (Ret != ERROR_ALREADY_EXISTS)
return Ret;
}
LPRASDEVINFO ras_devices;
DWORD cb =sizeof(RASDEVINFO);
DWORD cbDevices = 0;
ras_devices = (LPRASDEVINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
if (NULL == ras_devices)
{
printf("HeapAlloc failed.\n");
return ERROR_OUTOFMEMORY;
}
ras_devices->dwSize = sizeof(RASDEVINFO);
if ((Ret = RasEnumDevices(ras_devices, &cb, &cbDevices)) != ERROR_SUCCESS)
{
printf("RasEnumDevices failed with error %d\n", Ret);
switch(Ret)
{
case ERROR_BUFFER_TOO_SMALL:
printf("buffer too small");
HeapFree(GetProcessHeap(), 0, (LPVOID)ras_devices);
ras_devices = (LPRASDEVINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
if (NULL == ras_devices)
{
printf("HeapAlloc failed.\n");
return ERROR_OUTOFMEMORY;
}
ras_devices->dwSize = sizeof(RASDEVINFO);
Ret = RasEnumDevices(ras_devices, &cb, &cbDevices);
if (ERROR_SUCCESS == Ret)
{
//fSuccess = TRUE;
}
else
{
printf("RasEnumDevices failed again: Error = %d\n", Ret);
return Ret;
//goto done;
}
break;
case ERROR_NOT_ENOUGH_MEMORY:
printf("ERROR_NOT_ENOUGH_MEMORY");
return Ret;
break;
case ERROR_INVALID_PARAMETER:
printf("ERROR_INVALID_PARAMETER");
return Ret;
break;
case ERROR_INVALID_USER_BUFFER:
printf("ERROR_INVALID_USER_BUFFER");
return Ret;
break;
}
}
DWORD dwVpnStrategy = 0;
char device_name_mask[5];
strcpy(device_name_mask, "");
gboolean preshared_key_valid = 0;
switch(connection_type)
{
case PPTP:
strcpy(device_name_mask, "PPTP");
dwVpnStrategy = VS_PptpOnly;
break;
case L2TP:
if (preshared_key == 0 || strlen(preshared_key) == 0)
{
printf("CRITICAL: preshared key not set.");
return 1;
}
else
{
preshared_key_valid = TRUE;
}
strcpy(device_name_mask, "L2TP");
dwVpnStrategy = VS_L2tpOnly;
break;
}
int i =0;
for (i = 0; i < cbDevices; i++)
{
RASDEVINFO r = ras_devices[i];
if (strstr(r.szDeviceName, device_name_mask))
{
break;
}
}
//lpRasEntry->dwfOptions |= RASEO_SpecificIpAddr;
//lpRasEntry->szLocalPhoneNumber = RASDT_Vpn;
lpRasEntry->dwfNetProtocols |= RASNP_Ip;
lpRasEntry->dwFramingProtocol = RASFP_Ppp;
lstrcpy(lpRasEntry->szDeviceType, RASDT_Vpn);
lstrcpy(lpRasEntry->szDeviceName, ras_devices[i].szDeviceName);
lstrcpy(lpRasEntry->szLocalPhoneNumber, server_address);
lpRasEntry->dwVpnStrategy = dwVpnStrategy; // VS_PptpOnly; VS_SstpOnly
if (preshared_key_valid)
{
L2TP_CONFIG_DATA* data = GlobalAlloc(GPTR, sizeof(L2TP_CONFIG_DATA));
lpRasEntry->dwfOptions2 |= RASEO2_UsePreSharedKey;
data->dwOffsetKey = 16;
memcpy((PBYTE)data + data->dwOffsetKey, preshared_key, strlen(preshared_key));
data->dwAuthType =L2TP_IPSEC_AUTH_PRESHAREDKEY;
RasSetCustomAuthData(NULL, APP_NAME, data, sizeof(L2TP_CONFIG_DATA));
}
if ((Ret = RasSetEntryProperties(NULL, APP_NAME, lpRasEntry, EntryInfoSize, lpDeviceInfo, DeviceInfoSize)) != 0)
{
printf("RasSetEntryProperties failed with error %d\n", Ret);
return Ret;
}
//if ((Ret = RasSetCredentials(NULL, lpRasEntry.))
}
I cant find where is buffer to fill for pre-shared key.
Following code works fine.
// l2tp
if (preshared_key_valid)
{
RASCREDENTIALS ras_cre_psk = {0};
ras_cre_psk.dwSize = sizeof(ras_cre_psk);
ras_cre_psk.dwMask = 0x00000010; //RASCM_PreSharedKey;
wcscpy(ras_cre_psk.szPassword, preshared_key);
if ((Ret = RasSetCredentials(NULL, APP_NAME, &ras_cre_psk, FALSE)))
{
printf("RasSetCredentials failed with error %d\n", Ret);
return Ret;
}
}

Resources