system call return values and errno - c

I am using following system calls in my program:
recvfrom
sendto
sendmsg
And from each system call mentioned above I check if it completes with out any interruption and in case if it is interrupted, I retry.
Ex:
recvagain:
len = recvfrom(fd, response, MSGSIZE, MSG_WAITALL, (struct sockaddr *)&from, &fromlen);
if (errno == EINTR) {
syslog(LOG_NOTICE, "recvfrom interrupted: %s", strerror(errno));
goto recvagain;
}
Problem here is that do I need to reset errno value to 0 each and every time it fails. Or if recvfrom() is successful, does it reset errno to 0?
recvfrom() man page says:
Upon successful completion, recvfrom() returns the length of the message in bytes. If no messages are available to be received and the
peer has performed an orderly shutdown, recvfrom() returns 0.
Otherwise the function returns -1 and sets errno to indicate the
error.
same case with sendto and sendmsg.
I can n't really check this now as I don't have access to server-client setup.
Any idea?
Thanks

recvfrom returns -1 if it is interrupted (and sets errno to EINTR). Therefore, you should just check len:
if(len == -1) {
if(errno == EINTR) {
syslog(LOG_NOTICE, "recvfrom interrupted");
goto recvagain;
} else {
/* some other error occurred... */
}
}

The errno pseudo "variable" may not change on successful syscalls. So you could clear it either before your recvfrom, or when len<0 and having tested its value.
See errno(3) man page for more.
Actually, as Robert Xiao (nneonneo) commented, you should not write errno and just test it when the syscall has failed (in that case, the C function -e.g. recvfrom etc...- wrapping that syscall would have written errno before returning -1).

Related

How to know which case happens when nonblocking recv returns 0?

I have simple TCP server that runs with non-blocking sockets.
Quote from manpage of recv;
When a stream socket peer has performed an orderly shutdown, the return value will be 0 (the traditional "end-of-file" return).
The value 0 may also be returned if the requested number of bytes to receive from a stream socket was 0.
When socket is readable I read it with this code:
uint8_t buf[2048];
ssize_t rlen;
while(1){
rlen = recv(fd, buf, sizeof(buf), 0);
if(rlen < 0){
/* some error came, let's close socket... */
}
else if(rlen == 0){
/* is there no bytes to read? do we need break; in here? */
/* is socket closed by peer? do we need to close socket? */
}
/* some code that process buf and rlen... */
}
How we can know which case happens when recv returns 0?
When recv returns 0 it means that the socket has been gracefully closed by the other peer and can be closed from your side as well. When no data is present in socket, -1 is returned and errno is set to EAGAIN / ETIMEDOUT and the socket hasn't to be closed.
Finally, when -1 is returned and errno is set to a value different from EWOULDBLOCKor EAGAIN the socket has to be closed, because some unrecoverable error occurred.For non-blocking sockets it means that no data is immediately available when recv is called. For blocking sockets) it means tgat no data is available even after the timeout (SO_RCVTIMEO) previously set with setsockopt() expired.
As you correctly quoted in your last edit, 0 can be returned from recv also if the requested size is 0.
How we can know which case happens when recv returns 0?
Just test the provided recv size (in this case it is the size of a constant array, so it doesn't make much sense; but in case it is a variable coming from elsewhere...):
bufSize = sizeof(buf);
/* further code that, who knows, might affect bufSize */
rlen = read(fd, buf, bufSize);
if(rlen < 0){
if (errno != ETIMEDOUT && errno != EWOLUDBLOCK)
{
/* some error came, let's close socket... */
}
}
else if(rlen == 0){
if (bufSize != 0)
{
/* Close socket */
}
}

Can it realistically happen that for an UDP socket, the send function doesn't fail, but still writes less data than requested?

From man 2 sendto:
On success, these calls return the number of bytes sent. On error, -1 is returned, and errno is set appropriately.
Am I to understand that failure to write all data is not treated as a failure of these functions, therefore it realistically may happen that when writing to an UDP socket, the send() function writes less data than requested, but the reason of this failure is not specified in errno?
Or can I presume that send() will either return -1 and set errno appropriately, or return the number of bytes requested to send?
In other words: Is this error handling code sufficient:
if(send(udp_sock_fd, buf, buflen, 0) == -1) {
int err = errno;
fprintf(stderr, "Send failed:\n");
fprintf(stderr, strerror(err));
}
Or is it rather necessary to write something like that:
ssize_t bytes_send = send(udp_sock_fd, buf, buflen, 0);
if(bytes_send == -1) {
int err = errno;
fprintf(stderr, "Send failed:\n");
fprintf(stderr, strerror(err));
} else if(bytes_send < buflen) {
fprintf(stderr, "Incomplete send for unknown reason.\n");
}
There is no concept of sending just part of a datagram. It either all goes, or none of it goes. The OS or network drivers will not split the datagram for you. Returning the character count sent must just be a courtesy, to fall inline with other send API functions.
Also from the man page:
For sendto(), if the message is too long to pass atomically through the underlying protocol, the error EMSGSIZE is returned, and the message is not transmitted.
Obviously, #Paul Bentley has already provided the correct answer, but in case you're worried that -- even though this is never supposed to happen -- there might be some rare error condition where it does, it may be helpful to note that at least for a particular implementation (Linux), the code for udp_sendmsg in net/ipv4/udp.c (which is what's ultimately called for a send on a UDP socket) has only one exit that can return a non-negative value, and it returns the length supplied by the caller:
int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
{
... code that doesn't modify len ...
out:
...
if (!err)
return len;
...
}

Getting error number returned by recv function

How can I get the error number or error string returned by the recv() in socket communication, recv() returns -1 as read size which means some error has occurred. I want to know the specific reason for the error. so how can I get that.
You need to include errno.h and use the errno global variable to check the last error code. Also, you can use strerror() to print a locale aware string explaining the error.
Example
#include <errno.h>
ssize_t size;
if ((size = recv( ... )) == -1)
{
fprintf(stderr, "recv: %s (%d)\n", strerror(errno), errno);
}
You can make use of the errno variable from errno.h header file.
From the man page (emphasis mine)
Return Value
Upon successful completion, recv() shall return the length of the message in bytes. If no messages are available to be received and the peer has performed an orderly shutdown, recv() shall return 0. Otherwise, -1 shall be returned and errno set to indicate the error.
Alternatively, you can also call perror() / strerror() to get a human-readable string related to the error.

linux c socket error: Input/output error

I've got a "Input/output error" error when I try to send data to a tcp server. What does this mean in terms of sockets? Its basically the same code I was used always worked fine. I was hoping someone could tell me what are the reasons of inpput/output error when I tried to send over a socket and how I could check/fix them. Any help is appreciated.
struct SOCKETSTUS {
int sendSockFd;
int recvSockFd;
short status;
long heartBeatSendTime;
long heartBeatRecTime;
long loginPackSendTime;
};
struct SOCKETSTUS sockArr[128];
if (tv.tv_sec - sockArr[i].heartBeatSendTime >= beatTim)
{
if (send(sockArr[i].sendSockFd, szBuffer, packetSize, 0) != packetSize)
{
fprintf(stderr, "Heartbeat package send failed:[%d][%s]\n", errno, strerror(errno));
if (errno == EBADF || errno == ECONNRESET || errno == ENOTCONN || errno == EPIPE)
{
Debug("link lose connection\n"); Reconn(i); continue;
}
}
else
{
sockArr[i].heartBeatSendTime = tv.tv_sec;
if (sockArr[i].status == SOCK_IN_FLY)
sockArr[i].heartBeatRecTime = tv.tv_sec;
}
}
The error occured in send() calls.
Your error check is incorrect. send() returns the number of bytes sent or -1 on error. You check only that the return value equals packetSize, not that the return value indicates error. Sometimes send() on a stream socket will return fewer bytes than requested.
So, some previous syscall (perhaps a harmlessly failed tty manipulation? a dodgy signal handler?) set errno to EIO.
Change your code to treat -1 different from a "short" send.

socket select fails with operation in progress - Non blocking mode

Our application uses a non-blocking socket usage with connect and select operations (c code).
The pusedo code is as below
unsigned int ConnectToServer(struct sockaddr_in *pSelfAddr,struct sockaddr_in *pDestAddr)
{
int sktConnect = -1;
sktConnect = socket(AF_INET,SOCK_STREAM,0);
if(sktConnect == INVALID_SOCKET)
return -1;
fcntl(sktConnect,F_SETFL,fcntl(sktConnect,F_GETFL) | O_NONBLOCK);
if(pSelfAddr != 0)
{
if(bind(sktConnect,(const struct sockaddr*)(void *)pSelfAddr,sizeof(*pSelfAddr)) != 0)
{
closesocket(sktConnect);
return -1;
}
}
errno = 0;
int nRc = connect(sktConnect,(const struct sockaddr*)(void *)pDestAddr, sizeof(*pDestAddr));
if(nrC != -1)
{
return sktConnect;
}
if(errno != EINPROGRESS)
{
int savedError = errno;
closesocket(sktConnect);
return -1;
}
fd_set scanSet;
FD_ZERO(&scanSet);
FD_SET(sktConnect,&scanSet);
struct timeval waitTime;
waitTime.tv_sec = 2;
waitTime.tv_usec = 0;
int tmp;
tmp = select(sktConnect +1, (fd_set*)0, &scanSet, (fd_set*)0,&waitTime);
if(tmp == -1 || !FD_ISSET(sktConnect,&scanSet))
{
int savedErrorNo = errno;
writeLog("Connect %s failed after select, cause %d, error %s",inet_ntoa(pDestAddr->sin_addr),savedErrorNo,strerror(savedErrorNo));
closesocket(sktConnect);
return -1;
}
.
.
.
.
.}
Problem statement
In the above code, the select fails with error code 115 which is "Operation in progress". I do not see any documentation on select failing with errno 115.
a. When does the select fails with error code 115 in non-blocking socket? Under what scenario?
b. Do we see any system logs which hints at this problem. Only concern for us me - I could not find any documented feature which describes such problem.
PS : We are using SUSE Linux 11 Enterprise Edition.
The errno EINPROGRESS isn't from select(), it is left over from the prior connect() operation. You enter the block that reports it if either select() returned -1 or the FD isn't set. All this means is that the connection is still in progress. errno is never cleared, only set.
Some thoughts on your code:
I think your condition below the select can be modified to check only to see, if select has returned a value greater than 0 and if that is the case, you can check output of getsockopt for the socket (for SOL_SOCKET and SO_ERROR) options (getsockopt(...,SOL_SOCKET, SO_ERROR,...,...)) to see if connect has not failed.
I am not very sure if the select will always return the socket as writable in case of a connection success. So, in your case, it may (only may) be the case that, the tmp variable is not -1 and the errno it is showing is the errno of the previous connect call.
Additional Reasons:
Another good reason is that, the destination address to which you are connecting is either not reachable, or doesn't have a server waiting at the specified address + port combination. In which case, you can try once with a blocking socket to see if that connects.
As far as I understand, you are trying to make a connection with timeout.
If so, there is a error in your code. After connect() call but before select() you should remove O_NONBLOCK option using fcntl(). Otherwise the select() will always return at once because the operations with your socket (which has O_NONBLOCK) would not block.
The EINPROGRESS which you read is probably generated not by select() but by previous connect() call.
You also should not use bind() call here because connect() implicitly binds your address to socket.

Resources