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
long
for optvalue as a parameter, but Solaris uses achar
instead.
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).