I’m trying to use setsockopt() on both Linux and Solaris in my ftp program.
Linux uses a long for optvalue as a parameter, but Solaris uses a char instead.
#ifdef sun
char val;
#else
long val;
#endif
#ifdef sun
val = 1;
size_t len = sizeof(char);
if(setsockopt(s_socket_fd, SOL_SOCKET, SO_REUSEADDR, &val, len) == -1) {
perror("Fail");
exit(1);
}
#else
val = 1;
size_t len = sizeof(long);
if(setsockopt(s_socket_fd, SOL_SOCKET, SO_REUSEADDR, &val, len) == -1) {
perror("Fail");
exit(1);
}
#endif
The program works fine in Linux, but reports “Invalid argument” in Solaris when creating the socket.
Advertisement
Answer
There are 2 issues appearing in the question:
Linux uses a
longfor optvalue as a parameter, but Solaris uses acharinstead.
TL;DR: you should use int everywhere.
in Solaris there can be slightly different definitions of setsockopt() depending on the version of Solaris and the library the program is linked against, for example Solaris 10’s setsockopt (3SOCKET), setsockopt (3XNET) and Solaris 11’s setsockopt (3SOCKET), setsockopt (3XNET). Linux’ manpage shares the same contents as Solaris’ (3SOCKET) manpages:
Most socket-level options utilize an int argument for optval. For setsockopt(), the argument should be nonzero to enable a boolean option, or zero if the option is to be disabled.
(3XNET) just doesn’t state the type for bolean option. Yet-an-other-UNIX (AIX) also has old *BSD and UNIX98/XOPEN versions, on a single page, where it’s an int for booleans. The confusion about using char comes from (*BSD-style) examples using a pointer cast to (char *) instead of (const void *), because the prototype is using char * for *BSD/3XNET. That doesn’t mean the parameter is char. As for long, beside not being in the definition, on architectures where long is not int that would be wrong. Note that Windows is apart from *NIX there.
size_t len = sizeof(char);
Beside the fact that sizeof val should be preferred, and can be used directly in setsockopt() without even the need to use len here in the first place, len is defined as int on Solaris (3XNET) and as socklen_t on Solaris (3SOCKET) and Linux, not size_t anywhere. Link to a possible explanation on why int became socklen_t with a brief (and wrong) passage via size_t. Using other types (such as size_t on Linux) might break on some architectures when size_t is not defined as int (see the 2 previous links).