Is a non-blocking connect guaranteed to fail with EINPROGRESS? - sockets

If I set up a socket for non-blocking operation, as follows:
int fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
int rc = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
...is connect guaranteed to fail with EINPROGRESS, or do I need to handle the case where it succeeds immediately?

Not necessarily. Connecting to 127.0.0.1 may connect or fail immediately.

You need to handle the case where it succeeds immediately. That's why it returns 0 or -1. The documentation doesn't make any exception about that for non-blocking mode.

Related

BSD socket connect + select (client)

There must be something wrong in the below code but I don't seem to be able to use a client connect, non blocking in combination with a select statement. Please ignore the below lack of error handling.
I seem to have two issues
1. select blocks until timeout (60) if I try to connect port 80 on an internet server
2. trying to connect a existing or non existing port on 127.0.0.1 always instantly returns the select with no way to distinction between success or failure to connect.
What am I missing in my understanding of BSD nonblocking in combination with select?
fd_set readfds;
FD_ZERO(&readfds);
struct timeval tv;
tv.tv_sec = 60;
tv.tv_usec = 0;
struct sockaddr_in dest;
int socketFD = socket(AF_INET, SOCK_STREAM, 0);
memset(&dest, 0, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr("127.0.0.1");
dest.sin_port = htons(9483);
long arg;
arg = fcntl(socketFD, F_GETFL, NULL);
arg |= O_NONBLOCK;
fcntl(socketFD, F_SETFL, arg);
if (connect(socketFD, (struct sockaddr *)&dest, sizeof(struct sockaddr))<0 && errno == EINPROGRESS) {
//now add it to the read set
FD_SET(socketFD, &readfds);
int res = select(socketFD+1, &readfds, NULL, NULL, &tv);
int error = errno;
if (res>0 && FD_ISSET(socketFD, &readfds)) {
NSLog(#"errno: %d", error); //Always 36
}
}
errno is set in your original attempt to connect -- legitimately: that is, it's in-progress. You then call select. Since select didn't fail, errno is not being reset. System calls only set errno on failure; they do not clear it on success.
The connect may have completed successfully. You aren't checking that though. You should add a call to getsockopt with SO_ERROR to determine whether it worked. This will return the error state on the socket.
One other important note. According to the manual page (https://www.freebsd.org/cgi/man.cgi?query=connect&sektion=2), you should be using the writefds to await completion of the connect. I don't know whether the readfds will correctly report the status.
[EINPROGRESS] The socket is non-blocking and the connection cannot
be completed immediately. It is possible to select(2)
for completion by selecting the socket for writing.
See also this very similar question. Using select() for non-blocking sockets to connect always returns 1

Winsock TCP connection, send fine but recv firewall blocked

I have an application that sends a GET request using winsock on port 80 using a TCP socket. A few users have reported an issue where no response is received, looking at network logs and seeing the network device is getting the data just the app isn't it was clear that the firewall was blocking it.
Having disabled the firewall it then worked fine but what I don't understand is why it was getting blocked. The connection is created from the users computer, it connects fine and sends (which I assumes automatically opens a port) so how can data be lost on the same connection when received? Should I be providing additional winsock settings? Or is there simply no way around stopping the firewall blocking an already active connection?
Here is a stripped down version of the winsock code
SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock == INVALID_SOCKET)
return -1;
struct sockaddr_in client;
memset(&client, 0, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(80);
client.sin_addr.s_addr = inet_addr(inet_ntoa(*addr_list[0]));
if (connect(sock, (struct sockaddr *)&client, sizeof(client)) < 0){
closesocket(sock);
return -1;
}
if (send(sock, buffer, buflength, 0) != buflength){
closesocket(sock);
return -1;
}
//get response
response = "";
int resp_leng = BUFFERSIZE;
while (resp_leng == BUFFERSIZE)
{
resp_leng = recv(sock, (char*)&buffer, BUFFERSIZE, 0);
if (resp_leng > 0)
response += std::string(buffer).substr(0, resp_leng);
else
return -1;
}
closesocket(sock);
Your while loop exits if a recv() returns less than BUFFERSIZE. This is wrong -- you must always assume that recv() can return any amount of data from 1 byte up to and including the supplied buffer size.

SO_KEEPALIVE: Detecting connection lost or terminated

I have multiple threads who have a socket open with a client application each. Each of those threads receive an instruction from a main thread to send commands to the client (commands could be run test, stop test, terminate session, exit....). Those threads are generic, they just have a socket per client and just send a command when the main thread asks it to.
The client could exit or crash, or network could be bad.
I have been trying to see how to figure out that my TCP session has ended per client. Two solutions that I have found that seem appropriate here.
1) Implement my own heartbeat system
2) Use keepAlive using setsockopt.
I have tried 2) as it sounds faster to implement, but I am not sure of one thing: Will SO_KEEPALIVE generate a SIGPIPE when connection is interrupted please? I saw that it should be the case but never received a SIGPIPE.
This is how my code looks:
void setKeepAlive(int sockfd) {
int optval;
optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
optval = 1;
setsockopt(sockfd, SOL_TCP, TCP_KEEPIDLE, &optval, sizeof(optval));
optval = 1;
setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, &optval, sizeof(optval));
optval = 1;
setsockopt(sockfd, SOL_TCP, TCP_KEEPINTVL, &optval, sizeof(optval));
}
And my code that accepts connection is as follows:
for (mNumberConnectedClients = 0; mNumberConnectedClients < maxConnections; ++mNumberConnectedClients) {
clientSocket = accept(sockfd, (struct sockaddr *) &client_addr, &clientLength);
// set KeepAlive on socket
setKeepAlive(clientSocket);
pthread_create(&mThread_pool[mNumberConnectedClients], NULL, controlClient, (void*) &clientSocket);
}
signal(SIGPIPE, test);
....
And the test function:
void test(int n) {
printf("Socket broken: %d\n", n);
}
test() never gets triggered. Is it my understanding that is wrong please? I am not sure if SIGPIPE gets generated or not. Thanks a lot.
If a keep-alive fails, the connection will simply be invalidated by the OS, and any subsequent read/write operations on that socket will fail with an appropriate error code. You need to make sure your reading/writing code is handling errors so it can close the socket, if it is not already doing so.

Winsock2 - how to open a TCP socket that allows recv() with MSG_WAITALL?

In this code:
// error checking is omitted
// init Winsock2
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
// connect to server
struct addrinfo *res = NULL, *ptr = NULL, hints;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
getaddrinfo(server_ip, "9999", &hints, &res);
SOCKET client_socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
connect(client_socket, res->ai_addr, (int)res->ai_addrlen);
freeaddrinfo(res);
res = NULL;
// read the data
unsinged int size1;
if (recv(client_socket, (char*)&size1, sizeof(int), MSG_WAITALL) == SOCKET_ERROR)
{
return WSAGetLastError();
}
(note the MSG_WAITALL flag in recv()) everything works fine, expect for recv(). WSAGetLastError() returns WSAEOPNOTSUPP.
MSDN states that
Note that if the underlying transport does not support MSG_WAITALL, or if the socket is in a non-blocking mode, then this call will fail with WSAEOPNOTSUPP. Also, if MSG_WAITALL is specified along with MSG_OOB, MSG_PEEK, or MSG_PARTIAL, then this call will fail with WSAEOPNOTSUPP. This flag is not supported on datagram sockets or message-oriented sockets.
But it doesn't look like I'm doing something from this list. Why my recv() call doesn't work?
it doesn't look like I'm doing something from this list.
Yes, you are - the very first item on the list:
the underlying transport does not support MSG_WAITALL
Microsoft's default TCP transport provider does not support MSG_WAITALL. recv(), and Winsock in general, is not limited to just Microsoft's TCP provider. It supports 3rd party providers, and any transport protocols that the provider supports - TCP, UDP, IPX, ICMP, RAW, etc.
When using Microsoft's TCP, if you want recv() to wait until all of the requested TCP data has been received, you have to set the socket to blocking mode (its default mode) and then set the flags parameter of recv() to 0. But even that is not guaranteed, recv() can return with fewer bytes than requested, so you should be prepared to call recv() in a loop until all intended bytes have actually been received.

client-server code. How to bind the data connection to a specific port

I am trying to do the following:
Let us say I start a TCPServer on machine X. Now, I want to connect to the TCPServer from machine Y, but I want to specify the ports (both sender and receiver), on which the data communication should take place. Also, the TCPServer handles multiple clients at the same time.
MachineX: ./TCPServer
MachineY: ./TCPClient -SP 5000 -DP 5000
I have written the code for a multithreaded server (using C UNIX), and it works fine. Basically, it spawns one thread per connection. But I am not sure how to include the above functionality.
Thank you for your time!
Prior to calling connect(), call bind().
I'm assuming you had to do this for the server code, right? Otherwise, how do you get your server (running on MachineX) to listen on port 5000.
In any case, here's a C example of binding to localhost port 5000.
Example:
int sock = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in addrRemote = {};
sockaddr_in addrLocal = {}; // zero init so that sin_addr is already INADDR_ANY;
int result;
addrLocal.sin_family = AF_INET;
addrLocal.sin_port = htons(5000);
result = bind(sock, (sockaddr*)&addrLocal, sizeof(addrLocal));
if (result < 0)
return;
addrRemote.sin_family = AF_INET;
addrRemote.sin_port = htons(5000);
addrRemote.sin_addr = <ip of MachineX in network byte order>;
result = connect(sock, (sockaddr*)&addrRemote, sizeof(addrRemote));
if (result < 0)
return;
It's assumed that TCPServer running on machine X is listening on port 5000.