Socket() Returns 0 in C Client Server Application

socket() returns 0 in C client server application

socket() returns -1 on error.

A return of 0 means socket() succeeded and gave you file descriptor 0. I suspect that one of the file descriptors that you close has file descriptor 0 and once it's closed the next call to a function that allocated a file descriptor will return fd 0 as it's available.

accept returns 0 for 2nd, 3rd, etc client

Problem solved! I was accidentally closing fd 0 in my code, which caused this weird behaviour. Now everything works. Thanks for helping - you've showed me the right way

C TCP sockets, can 'send' return 0 after using select?

Zero is never possible. It will either transfer at least one byte and return the cost, or return -1 with errno == EAGAIN/EWOULDBLOCK if the buffer is full in non-blocking mode, or -1 with some other errno if there is a bad error. It shouldn't give -1/EAGAIN/EWOULDBLOCK if select() has indicated otherwise, except in the presence of multithreaded writing to the socket.

why write() doesn't return 0 when it should?

The only way to make write return zero on a socket is to ask it to write zero bytes. If there's an error on the socket you will always get -1.

If you want to get a "connection closed" indicator, you need to use read which will return 0 for a remotely closed connection.

Socket read() function sometimes never returns 0 when processing tunneling

Your tunnel() loop is completely ignoring the return values of read() and write(). Try something more like this instead:

bool writeAll(int sckt, void *buffer, size_t buflen)
{
char *pbuffer = (char*) buffer;
while (buflen > 0)
{
ssize_t numSent = write(sckt, pbuffer, buflen);
if (numSent < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
continue;
return false;
}
pbuffer += numSent;
buflen -= numSent;
}
return true;
}

...

strcpy(buffer, "HTTP/1.0 200 Connection established\r\n\r\n");
if (writeAll(client, buffer, strlen(buffer)))
tunnel(server, client, buffer);
close(client);
close(server);
return;

...

void tunnel(int server, int client, char *buffer)
{
int maxFD = max(server, client) + 1;
ssize_t numRead;
FD_SET fd;

int x = fcntl(server, F_GETFL, 0);
fcntl(server, F_SETFL, x | O_NONBLOCK);

x = fcntl(client, F_GETFL, 0);
fcntl(client, F_SETFL, x | O_NONBLOCK);

do
{
cout << "test" << endl;

FD_ZERO(&fd);
FD_SET(&fd, server);
FD_SET(&fd, client);

x = select(maxFD, &fd, NULL, NULL, NULL);
if (x < 0) break;

if (FD_ISSET(&fd, client))
{
numRead = read(client, buffer, BUFSIZE);
if (numRead <= 0) break;

if (!writeAll(server, buffer, numRead))
break;
}

if (FD_ISSET(&fd, server))
{
numRead = read(server, buffer, BUFSIZE);
if (numRead <= 0) break;

if (!writeAll(client, buffer, numRead))
break;
}
}
while (true);
}

As for why your reads are not always returning 0 when you are expecting, that is most likely due to the client and server using an HTTP keep-alive to keep the tunnel connection open after the server has sent its response, so the client can send subsequent requests to the same server using the same TCP connection. Establishing a new TCP connection, and even a new HTTPS session, on every HTTP/S request is time-consuming and wastes bandwidth as it involves many round trips for the TCP and TLS handshakes. So the default behavior of HTTP 1.1 and later is to keep a connection open unless either party explicitly states a close is wanted via a Connection: close header.

Read system call returning zero bytes though the socket is ready for read

Without any code, it's hard to guess what exactly happens, but select() succeeding does not necessarily mean that some data are ready to be read.

select() just makes the promise that if you try one read from this file-descriptor you will not be blocked.
The reason might be any of these:

  • the kernel stores in an internal buffer some data to be delivered through the file-descriptor you read (it's what you are expecting here),
  • or the other end of the file-descriptor is closed, then no new data will ever be delivered (the EOF you observe),
  • or the file-descriptor is in an invalid state for a read operation and any read attempt will immediately fail (see errno after read).


Related Topics



Leave a reply



Submit