Reputation: 23
What could possible by the problem when the errno value is not updated during successive calls to socket functions?
socket (AF_INET, -1, 0);
socket (AF_INET, SOCK_STREAM, -1);
The first should have errno = EINVAL The second should have errno = EPROTONOSUPPORT
From the code provided below by @JonathanLeffler, output from cygwin is as follows:
*$ ./socket.exe
Error from socket(AF_INET, -1, 0): 124 (Socket type not supported)
-- errno = 124 (Socket type not supported)
Error from socket(AF_INET, SOCK_STREAM, -1): 123 (Protocol not supported)
-- errno = 123 (Protocol not supported)
socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = 3)
-- errno = 123 (Protocol not supported)*
The said code below was edited to create a socket fd0 before creating the socket
int fd0 = socket(AF_INET, SOCK_STREAM, 0);
if (fd0 < 0)
printf("Error from socket(AF_INET, SOCK_STREAM, 0): %d (%s)\n", errno, strerror(errno));
else
{
printf("socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = %d)\n", fd0);
close(fd0);
}
printf("-- errno = %d (%s)\n", errno, strerror(errno));
int fd1 = socket(AF_INET, -1, 0);
.....
And the result is as follows:
*$ ./socket.exe
socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = 3)
-- errno = 0 (No error)
Error from socket(AF_INET, -1, 0): 124 (Socket type not supported)
-- errno = 124 (Socket type not supported)
Error from socket(AF_INET, SOCK_STREAM, -1): 123 (Protocol not supported)
-- errno = 123 (Protocol not supported)
socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = 3)
-- errno = 123 (Protocol not supported)*
It is expected that the first and the last socket creation should have the same errno values.
But how can this output be explained? 5th and 6th socket creation have the same errno value but the cause of the error is different.
$ ./test_select.exe
[1] ierr = 124, iSocket = -1 socket(AF_INET, -1, 0);
: Socket type not supported
[2] ierr = 124, iSocket = -1 socket(AF_INET, -1, 0);
: Socket type not supported
[3] ierr = 124, iSocket = 3 socket(AF_INET, SOCK_STREAM, 0);
: Socket type not supported
[4] ierr = 124, iSocket = -1 socket (AF_INET, -1, 0);
: Socket type not supported
[5] ierr = 123, iSocket = -1 socket (AF_INET, SOCK_STREAM, -1);
: Protocol not supported
[6] ierr = 123, iSocket = -1 socket (AF_INET, -1, 0)
: Protocol not supported
[7] ierr = 124, iSocket = -1 socket(AF_INET, SOCK_STREAM, -1)
: Protocol not supported
Actual code is as follows:
sockfd = socket(AF_INET, -1, 0);
err = errno;
printf("[1] err = %d, sockfd = %d socket(AF_INET, -1, 0);\n", err, sockfd);
perror(" ");
sockfd = socket(AF_INET, -1, 0);
err = errno;
printf("[2] err = %d, sockfd = %d socket(AF_INET, -1, 0);\n", err, sockfd);
perror(" ");
sockfd = socket(AF_INET, SOCK_STREAM, 0);
err = errno;
printf("[3] err = %d, sockfd = %d socket(AF_INET, SOCK_STREAM, 0);\n", err, sockfd);
perror(" ");
close(sockfd);
sockfd = socket(AF_INET, -1, 0);
err = errno;
printf("[4] err = %d, sockfd = %d socket (AF_INET, -1, 0);\n", err, sockfd);
perror(" ");
sockfd = socket(AF_INET, SOCK_STREAM, -1);
err = errno;
printf("[5] err = %d, sockfd = %d socket (AF_INET, SOCK_STREAM, -1);\n", err, sockfd);
perror(" ");
sockfd = socket(AF_INET, -1, 0);
err = errno;
printf("[6] err = %d, sockfd = %d socket (AF_INET, -1, 0)\n", err, sockfd);
perror(" ");
err = errno;
sockfd = socket(AF_INET, SOCK_STREAM, -1);
printf("[7] err = %d, sockfd = %d socket(AF_INET, SOCK_STREAM, -1)\n", err, sockfd);
perror(" ");
Upvotes: 2
Views: 1928
Reputation: 753475
No library function sets errno
to zero. If you want it zeroed, your program must do it.
You can only meaningfully test errno
for information when a function says it has failed (and even then, only if its manual page indicates that it sets errno
). You can find errno
set to non-zero by a successful function. For example, on Solaris, you'll often find ENOTTY in errno
after a standard I/O call when writing to a file instead of a terminal.
In your example, there's no guarantee about which of multiple possible error values will be set by a given erroneous call to a function. As long as one valid error condition is reported, it is up to the system to decide which error it reports. So, you'd need to give a compelling example of why the second call should return EINVAL instead of EBADF; your question as written doesn't include enough information to let us pontificate.
Also note that the only safe way to declare errno
is via the header: #include <errno.h>
. In threaded environments in particular, it is often not simply extern int errno;
. For example, on Mac OS X, it can be defined as:
extern int * __error(void);
#define errno (*__error())
That is, __error
is a function returning a pointer to an integer, and errno
is a macro that dereferences that pointer, becoming a modifiable lvalue.
The given code is:
socket (AF_INET, -1, 0);
socket (AF_INET, SOCK_STREAM, -1);
Converted into runnable code, this might become:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
int main(void)
{
int fd1 = socket(AF_INET, -1, 0);
if (fd1 < 0)
printf("Error from socket(AF_INET, -1, 0): %d (%s)\n", errno, strerror(errno));
else
{
printf("socket(AF_INET, -1, 0) succeeded (fd = %d)\n", fd1);
close(fd1);
}
printf("-- errno = %d (%s)\n", errno, strerror(errno));
int fd2 = socket(AF_INET, SOCK_STREAM, -1);
if (fd2 < 0)
printf("Error from socket(AF_INET, SOCK_STREAM, -1): %d (%s)\n", errno, strerror(errno));
else
{
printf("socket(AF_INET, SOCK_STREAM, -1) succeeded (fd = %d)\n", fd2);
close(fd2);
}
printf("-- errno = %d (%s)\n", errno, strerror(errno));
int fd3 = socket(AF_INET, SOCK_STREAM, 0);
if (fd3 < 0)
printf("Error from socket(AF_INET, SOCK_STREAM, 0): %d (%s)\n", errno, strerror(errno));
else
{
printf("socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = %d)\n", fd3);
close(fd3);
}
printf("-- errno = %d (%s)\n", errno, strerror(errno));
return(0);
}
Running on Mac OS X 10.7.3, this produces:
Error from socket(AF_INET, -1, 0): 43 (Protocol not supported)
-- errno = 43 (Protocol not supported)
Error from socket(AF_INET, SOCK_STREAM, -1): 43 (Protocol not supported)
-- errno = 43 (Protocol not supported)
socket(AF_INET, SOCK_STREAM, 0) succeeded (fd = 3)
-- errno = 43 (Protocol not supported)
As I said earlier, the error returned depends on the system.
Upvotes: 9
Reputation: 215193
errno
is never cleared by standard library functions, only set. Furthermore, it can be spuriously set by any standard library function that is not otherwise documented to disallow that behavior.
Essentially, the only correct way to use errno
is to only inspect it immediately after a standard library function returns a value indicating an error, and save it in another variable if you need to keep it around for later.
With select
and most system calls, the return value indicating an error is -1, meaning you should only inspect errno
if it returns -1.
Upvotes: 11