Skip to content
Advertisement

setsockopt usage in Linux and Solaris [Invalid argument in Solaris]

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 a char 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).

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement