Strange "getsockopt" Solaris behavior

Please take a look on following code:

    s = socket(PF_INET, SOCK_STREAM, 0);    //socket
    fcntl(s, F_SETFL, O_NONBLOCK);             //set socket to nonblock

retry_conn:    
    ret = connect(s, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr_in)); // try to connect, for sure there no connection to "serv_addr" 
    printf("connect, status=%d, errno=%d \n", status, errno); 
    
    if (errno == EINPROGRESS) //no connection
    {
        if (poll(fds, 1, delay_time / 1000) > 0)
        {
            ret = getsockopt(s, SOL_SOCKET, SO_ERROR, &error_s, &len_s)
            printf("getsockopt, status: %d, error_s=%d, errno=%d\n", status, error_s, errno);
        }
        
        if (error_s)
        {
            printf("try_connect_again\n");
            goto: try_connect_again;
        }
        else
        {
            connected!!!!!!!!!
        }
    }

And now, what is the problem. When "connect" is executed for the first time (return code = 150), "getsockopt" in "error_s" return code "146", but after "goto"
when "getsockopt" is executed second time "error_s" is equal "0" (which means connection is established successfully).

Example output:

    connect, status=-1, errno=150
    getsockopt, status: 0, error_s=146, errno=150
    try_connect_again
    connect, status=-1, errno=150
    getsockopt, status: 0, error_s=0, errno=0

The same code executed on i.e. Linux CentOS or HPUX, when getsockopt is executed second time, return error codes and inform that there is no connection but in case of Solaris
"getsockopt" works in a strange way.

Please explain what is the problem or how to deal with such behavior on Solaris.

Thanks in advance.

Your sample output does not match what the code you posted would emit. There's no "try connect again!" in your sample output, yet your code would have printed that given the value of errno_s.

Not only that, your code would not compile as the else clause following the goto statement is not valid C or C++ code.

It's hard to know what's going on when the code you post can not produce the output you're seeing.

Also, why are you assuming errno will be reset to zero? Few if any library calls will do that, especially on Solaris, which follows POSIX and other specifications MUCH more closely than Linux does.

In addition to what achenle has already said:

  1. you are missing a ; after the call to getsockopt(),
  2. there is no : in a goto statement, and
  3. there is no label try_connect_again .

It is just a pseudo-code - to show what is the main problem.

connect -> poll -> getsockopt \(return errno_s = 146 - correct\) -> connect -> poll -> getsockopt \(return errno_s = 0\)

When "getsockopt" is executed second time, for some reason "optval" (errno_s) is equal "0".

OK. So you showed us imaginary output from pseudo-code that won't compile and has never been run. That makes it hard for us to imagine what problems you might run into if you wrote working code and actually looked at the output it might produce.

If you have code that did produce the output you showed us, show us that code! If not, write some code, compile it, run it, and show us the code and the output that was produced by running that code.

We see nothing at all strange about the output produced by getsockopt() on a Solaris system from the pseudo-code you've shown us. If we don't know what you passed to getsockopt(), we can't guess at what any OS might do with the data it was given.

First, thanks for your interest

#include <assert.h>
#include <sys/fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/devpoll.h>
#include <unistd.h>
#include <netinet/in.h>
#include <netinet/in.h>
#include <netinet/ip.h> 
#include <sys/socket.h>
#include <netinet/tcp.h>

int main()
{
    int fd = -1;
    int ret = 0;
    int error_s = 0;
    struct sockaddr_in serv_addr;
    int delay_time = 3000;
    int len_s = sizeof(int);
    int try = 3;
    
    fd = socket(PF_INET, SOCK_STREAM, 0);
    fcntl(fd, F_SETFL, O_NONBLOCK);
    printf("fd=\"%d\" \n", fd);
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(45678);
    serv_addr.sin_addr.s_addr = inet_addr("10.0.0.5");
    
try_connect_again:

    printf("try_connect_again\n");
    printf("attempt left %d ...\n", try);
    if (!try)
        goto fin;
        
    usleep(2000);
    ret = connect(fd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr_in));
    printf("connect ret=%d, errno=%d\n", ret, errno);
    
    if (errno == EINPROGRESS)
    {
        do
        {
            struct pollfd fds;

            fds.fd = fd;
            fds.events = POLLIN | POLLOUT;
            ret = poll(&fds, 1, delay_time);
            
            if (ret == -1) //poll error
            {
                goto fin;
            }
        }
        while (!ret);
        
        if (ret)
        {
            ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error_s, &len_s);
            printf("getsockopt, ret=%d, error_s=%d \n", ret, error_s);
            if (error_s == 0)
                printf("connected\n");
            else
            {
                try--;
                goto try_connect_again;
            }
        }
        else if (ret == 0)
        {
            try--;
            goto try_connect_again;
        }
    }

fin:
    printf("end\n");
    return 0;
}

gcc -lsocket -lresolv -lnsl -g -o test1 test1.c

Above code generate following output:

I can't find the reason, why getsockopt works different during second attempt.

Add a printf() to show what poll() returns...

"poll()" working as expected and for both attempt return "1" (one socket added to poll() so ok).