winsock2 accepting clients without calling accept function - c++

I'm trying winsock example from Microsoft docs,
client code
https://learn.microsoft.com/en-us/windows/win32/winsock/complete-client-code
server code
https://learn.microsoft.com/en-us/windows/win32/winsock/complete-server-code
Problem I'm facing is connect function in client code returns valid socket fd without accepting from server side, I removed the accept function but client still able to connect and return valid socket fd.
iResult = listen(ListenSocket, SOMAXCONN);
if (iResult == SOCKET_ERROR) {
printf("listen failed with error: %d\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
while (1)
{
Sleep(1000);
}
Any help is appreciated

If listen() returns success, the OS will accept requests for new connections for you in the background and put the new connections into an internal queue, which accept() will then pull from. So, even if the server code never calls accept(), new connections will still be accepted in the background as long as the queue is not full. If the queue does fill up, subsequent requests for new connections will fail with a (WSA)ECONNREFUSED error.

Related

client socket is bindable but not connectable, because already in use

I write a client, where i have to bind the client socket. This works fine. After that i try to connect the Socket and i get error 10048. (Address already in use.) I don't understand how this is possible.
I have to implement a client speaking with multiple server. Every server only accepts messages from a specific port. (every Server expects a different port). so i have to bind my client socket. The code above is to create one of these sockets.
My code works some times. But very often the connect gives me the error 10048, while the binding before was fine. I know that bind can give also the error 10048 if the socket is already in use. But it doesn't. It returns 0. So i guess the port is free. Immediate after binding i call connect and get error 10048. I do not understand why? At the moment of the binding the port was obviously free.
bool TEthernetSocket::Open()
{
WSADATA wsaData;
if (WSAStartup((MAKEWORD(2, 0)), &wsaData) == SOCKET_ERROR)
{
return IsConnected();
}
Socket = socket(AF_INET, SOCK_STREAM, 0); // TCP
if (Socket == INVALID_SOCKET)
{
return false;
}
//bind Socket
struct sockaddr_in sa_loc;
memset(&sa_loc, 0, sizeof(struct sockaddr_in));
sa_loc.sin_family = AF_INET;
sa_loc.sin_port = htons(ClientPort);
sa_loc.sin_addr.s_addr = inet_addr(IPClient.substr(0, 15).c_str());
CALL_TRACE_CB("ethernetSocket connected");
if (!(bind(Socket, (struct sockaddr*)&sa_loc, sizeof(struct
sockaddr))))
{
CALL_TRACE_CB("Bind works");
}
else
{
AnsiString msg = AnsiString().sprintf("EN: error socket Bind:
%d", WSAGetLastError());
CALL_ERROR_CB(ERROR_NO_PORT_HANDLE, msg.c_str());
Close();
}
// TCP
SOCKADDR_IN sAdd;
sAdd.sin_family = AF_INET;
sAdd.sin_port = htons(Port);
sAdd.sin_addr.s_addr = inet_addr(IP.substr(0, 15).c_str());
if (connect(Socket, (SOCKADDR*)&sAdd, sizeof(SOCKADDR_IN)) ==
SOCKET_ERROR)
{
AnsiString msg = AnsiString().sprintf("EN: error connect
errorcode: %d", WSAGetLastError());
}
}
I expect that bind() returns 10048 before connect returns this error, but actual only connect() returns this error
I have to implement a client speaking with multiple server. The server only accepts messages from a specific port, so i have to bind my client socket.
This is an unsolvable problem. When you make an outbound TCP connection, the combination of local IP address and port is reserved exclusively for that particular outbound TCP connection. If you need to make multiple outbound TCP connections from the same port, each will have to be bound to its own local IP address. That is going to be extremely inconvenient.
There are other problems too. Say you finish one connection and then try to start a new one. The new one will have the same local IP address, local port (since the server only tolerates one), remote IP address, and remote port. How will packets from the new connection be distinguished from old, stale packets from the old one?
This is why you get the error when you try to connect. It's not until all four parameters of the connection (local and remote address and local and remote port) are known that the collision with the prior connection is detectable. That's not known until you call connect.
You need to fix the server to ignore the source port. If that absolutely cannot be done, you'll have to adopt a wait and retry mechanism to handle collisions with past connections.

what happand to socket, when the other end close it?

I want to develop a client server app and I want to make it as robust as possible. There are multiple questions come up for me, and I just can't find an unambiguous answer on the internet.
Let's say, that the server is running on a while(TRUE) loop and check for command existance is it's commands queue, if there is one, it sends it, if there isn't one, it just continue to the head of the loop.
But what if the other end went down, or there is a connection error between the two, what happen to the socket value, does it become INVALID_SOCKET?
while (TRUE) {
if (ReqQueue->size() != 0 && ReqQueue->front() != string("STOP")) { // there is some command in the ReqQueue which is NOT STOP.
int sent = send(ClientSocket, ReqQueue->front().c_str(), (int)strlen(ReqQueue->front().c_str()), 0);
if (sent == (int)strlen(ReqQueue->front().c_str()))
ReqQueue->pop(); // Next Command.
else if (int err = WSAGetLastError() == WSAETIMEDOUT){
shutdown(ClientSocket, SD_BOTH);
closesocket(ClientSocket);
return;
}
else
continue;
}
else if (ReqQueue->size() == 0) {
continue;
}
else if(ReqQueue->front() == string("STOP"))
{
if (send(ClientSocket, "STOP", strlen("STOP"), 0) == strlen("STOP")) {
/*Message received indication from target*/
shutdown(ClientSocket, SD_BOTH);
closesocket(ClientSocket);
return;
}
}
}
shutdown(ClientSocket, SD_BOTH);
closesocket(ClientSocket);
return 0;
that's the source :)
what I want to ask is, there is a better way to implement the above goal, maybe I can change the while loop condition to something like while(the socket is OK) or while(there is still a connection).
what happen to the socket value
Nothing. A send() on that socket will eventually fail, and a recv() on it will deliver zero or -1, but the socket itself remains open, and the variable value is unaffected. There is no magic.
does it become INVALID_SOCKET?
No.
For me, better idea would be when you receive a request to your server from any client, just create a new thread and assign the task to that thread. By doing that you can make your server parallel processing of client request and work on multiple request from multiple client. Hence no client need to wait for server to complete the request of a client already submitted a request. If you implement like this you don’t need to bother what will happened if a connection broken. In normal case if a correction broken you will get this information in your server while sending the reply to the client and you can mark that process as failed and log it into server log.

If a winsock2 socket is non-blocking, would an SSL object associated with it also exhibit non-blocking behavior?

I'm asking this question because I am unsure whether an SSL object treats a socket as a sink/source for messages like it does with a BIO object. My gut is telling me yes, but I'm not certain.
Goal:
I am integrating a SSL authentication into already existing TCP code. Rather than calling the conventional send()/receive(), I would like to direct the messages through OpenSSL's SSL_read()/SSL_write() instead. My other requirement is that communication is non-blocking and data can be partially sent.
Here's how I've associated the SSL object with the socket (Server code).
SSL_Init(std::wstring &peer_hostname, SOCKET sock){
//...
//Initialize SSL structure
ssl = SSL_new(context);
if (ssl == NULL){
mr = APPZRETURN(E_FAIL, L"%ls (%d) : SSL_new failed. Unable to create SSL structure", __FUNCTIONW__, __LINE__);
}
//Agent uses winsock class, but OpenSSL uses unix socket. Surpressed warning added here for 4244. It works
if (SSL_set_fd(ssl, sock) == 0){ //set file descriptor for ssl
//Operation failed
return -1;
}
//...
int status = SSL_accept(ssl);
SSL_set_mode(ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER|SSL_MODE_ENABLE_PARTIAL_WRITE);
//...
}
According to the documentation for SSL_read() [https://www.openssl.org/docs/ssl/SSL_read.html], the SSL is non-blocking if the underlying BIO is non-blocking. If my assumption is correct, does that mean if the socket is non-blocking, the SSL is as well?
Extension of my Question: Is a winsock tcp socket non-blocking by default (assuming I have created a TCP socket, but have not called ioctlsocket and set non-blocking mode)
Thank you for taking the time to read this. It's much appreciated.
If my assumption is correct, does that mean if the socket is non-blocking, the SSL is as well?
Yes.
Is a winsock tcp socket non-blocking by default (assuming I have created a TCP socket, but have not called ioctlsocket and set non-blocking mode)
Unix sockets are by default blocking. Haven't used Winsock. But am sure Winsock should be by default blocking.
try following code:
SSL_set_fd(ss, sock);
retry:
int ret = SSL_accept(ssl);
if (ret != 1) {
int err = SSL_get_error(ssl, ret);
if (err == SSL_ERROR_WANT_READ || SSL_ERROR_WANT_WRITE) {
// maybe need some sleep or select
goto retry;
}
}

Winsock not sending in a while loop

I am very new to networking and have an issue with sending messages during a while loop.
To my knowledge I should do something along the lines of this:
Create Socket()
Connect()
While
Do logic
Send()
End while
Close Socket()
However it sends once and returns -1 there after.
The code will only work when I create the socket in the loop.
While
Create Socket()
Connect()
Do logic
Send()
Close Socket()
End while
Here is a section of the code I am using but doesn't work:
//init winsock
WSAStartup(MAKEWORD(2, 0), &wsaData);
//open socket
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
//connect
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = inet_addr(ipaddress);
serveraddr.sin_port = htons((unsigned short) port);
connect(sock, (struct sockaddr *) &serveraddr, sizeof(serveraddr));
while(true) {
if (send(sock, request.c_str(), request.length(), 0)< 0 /*!= request.length()*/) {
OutputDebugString(TEXT("Failed to send."));
} else {
OutputDebugString(TEXT("Activity sent."));
}
Sleep(30000);
}
//disconnect
closesocket(sock);
//cleanup
WSACleanup();
The function CheckForLastError() returns:10053
WSAECONNABORTED
Software caused connection abort.
An established connection was aborted by the software in your host computer, possibly due to a data transmission time-out or protocol error
Thanks
I have been looking for a solution to this problem too. I am having the same problem with my server. When trying to send a response from inside the loop, the client seems never to receive it.
As I understand the problem, according to user207421's suggestions, when you establish a connection between a client and a server, the protocol should have enough information to let the client know when the server has finished sending the response. If you see this example, you have a minimum HTTP server that responds to requests. In this case, you can use a browser or an application like Postman. And if you see the response message, you will see a header called Connection. Setting its value to close tells the client which one is the last message from the server for that request. The message is being sent, but the client keeps waiting, maybe because there is no closing element the client can recognize. I was also missing the Content-Length header. My HTTP response message was wrong, and the client was lost.
This diagram shows what needs to be outside the loop and what needs to be inside.
To understand how and why your program fails,you have to understand the functions you use.
Some of them are blocking functions and some are them not. Some of them need previous calles of other functions and some of them don't.
Now from what i understand we are talking about a client here,not a server.
The client has only non blocking functions in this case. That means that whenever you call a function,it will be executed without waiting.
So send() will send data the second it is called and the stream will go on to the next line of code.
If the information to be sent was not yet ready...you will have a problem,since nothing will be sent.
To solve it you could use some sort of a delay. The problem with delays is that they are Blocking functions meaning your stream will stop once it hits the delay. To solve it you can create a thread and lock it untill the information is ready to be sent.
But that would do the job for one send(). You will send the info and thats that.
If you want to hold the communication and send repeatedly info,you will need to create a while loop. once you have a while loop you dont have to worry about anything. That is because you can verify that the information is ready with a stream control and you can use send over and over again before terminating the connection.
Now the question is what is happening on the server side of things?
"ipaddress" should hold the ip of the server. The server might reject your request to connect.Or worst he might accept your request but he is listening with diffrent settings in relation to your client.Meaning that maybe the server is not reciving (does not have recv() function)information and you are trying to send info... that might resault in errors/crashes and what not.

How to deal with short reads with Winsock2?

I'm having trouble with receiving data over a network using Winsock2, with Windows. I'm trying to use a simple client and server system to implement a file transfer program. With our current code, the last packet coming in doesn't get appended to the file because it's not the size of the buffer. So, the file transfer doesn't quite completely, throws an error, and breaks. It's not always the very last packet, sometimes it's earlier.
Here is a snippet of the Server code:
int iResult;
ifstream sendFile(path, ifstream::binary);
char* buf;
if (sendFile.is_open()) {
printf("File Opened!\n");
// Sends the file
while (sendFile.good()) {
buf = new char[1024];
sendFile.read(buf, 1024);
iResult = send(AcceptSocket, buf, (int)strlen(buf)-4, 0 );
if (iResult == SOCKET_ERROR) {
wprintf(L"send failed with error: %d\n", WSAGetLastError());
closesocket(AcceptSocket);
WSACleanup();
return 1;
}
//printf("Bytes Sent: %d\n", iResult);
}
sendFile.close();
}
And here is a snippet of the Client code:
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
char recvbuf[DEFAULT_BUFLEN] = "";
do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen, 0);
if ( iResult > 0){
printf("%s",recvbuf);
myfile.write(recvbuf, iResult);
}
else if ( iResult == 0 ) {
wprintf(L"Connection closed\n");
} else {
wprintf(L"recv failed with error: %d\n", WSAGetLastError());
}
} while( iResult > 0 );
myfile.close();
When trying to transfer a file that is a dictionary, it can break at random times. For example, one run broke early in the S's and appended weird characters to the end, which isn't rare:
...
sayable
sayer
sayers
sayest
sayid
sayids
saying
sayings
╠╠╠╠╠╠╠╠recv failed with error: 10054
What can I do to handle these errors and weird characters?
The error is happening on the server side. You're getting a "Connection reset by peer" error.
This line - buf = new char[1024]; - is clearly problematic and is likely causing the server to crash because it runs out of memory. There is no clean up happening. Start by adding the appropriate delete statement, probably best placed after the send call. If that doesn't fix it I would use a small test file and step through that while loop in the server code.
P.S. A better solution than using new and delete in your loop is to reuse the existing buff. The compiler might optimize this mistake out but if it doesn't you're severely hindering the applications performance. I think you actually should just move buf = new char[1024]; outside of the loop. buf is a char pointer so read will continue to overwrite the contents of buf if you pass it buf. Re allocating the buffer over and over is not good.
With regard to the error MSDN says:
An existing connection was forcibly closed by the remote host. This normally results if the peer application on the remote host is suddenly stopped, the host is rebooted, the host or remote network interface is disabled, or the remote host uses a hard close (see setsockopt for more information on the SO_LINGER option on the remote socket). This error may also result if a connection was broken due to keep-alive activity detecting a failure while one or more operations are in progress. Operations that were in progress fail with WSAENETRESET. Subsequent operations fail with WSAECONNRESET.
First, using the new operator in a loop might not be good, especially without a corresponding delete. I'm not a C++ expert, though (only C) but I think it is worth checking.
Second, socket error 10054 is "connection reset by peer" which tells me that the server is not performing what is called a graceful close on the socket. With a graceful close, WinSock will wait until all pending data has been received by the other side before sending the FIN message that breaks the connection. It is likely that your server is is just closing immediately after the final buffer is given to WinSock without any time for it to get transmitted. You'll want to look into the SO_LINGER socket options -- they explain the graceful vs non-graceful closes.
Simply put, you either need to add your own protocol to the connection so that the client can acknowledge receipt of the final data block, or the server side needs to call setsocketopt() to set a SO_LINGER timeout so that WinSock will wait for the TCP/IP acknowledgement from the client side for the final block of data before issuing the socket close across the network. If you don't do at least ONE of those things, then this problem will occur.
There's also another article about that here that you might want to look at:
socket error 10054
Good luck!