Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Non-blocking connect() and error return on Solaris?

99 views
Skip to first unread message

Bill Fenner

unread,
Jul 3, 1996, 3:00:00 AM7/3/96
to

On BSD-based IP stacks, I can perform a sequence like:

s = socket(AF_INET, SOCK_STREAM, 0);
fcntl(s, F_SETFL, FNDELAY);
if (connect(s, &sin, sizeof sin) < 0 && errno != EINPROGRESS)
perror("connect");
... select on s for writing and do other stuff until s is ready
... for writing
getsockopt(s, SOL_SOCKET, SO_ERROR, &err, sizeof(err));
if (err != 0) {
errno = err;
perror("connect");
} else {
/* Connection succeeded */
}

The getsockopt(..., SO_ERROR, ...) gets me the errno from the
connect(), e.g. ETIMEDOUT, EHOSTUNREACH, or whatever. On Solaris, the
getsockopt() returns -1/EPIPE if the connect() failed. I work around
this right now by setting err to ENOTCONN if the getsockopt() fails, so
that it prints a vaguely generic error message, but I'd like to be able
to return the real error even under Solaris. Does anyone know how to
do this?

Thanks,
Bill

Bill Fenner

unread,
Jul 10, 1996, 3:00:00 AM7/10/96
to

I figured I'd post the solution, since I got a couple of queries in
private email. Rich Stevens was kind enough to point out that under
Solaris 2.5, getsockopt() returns -1 and sets errno to the connect()
error. I had experienced my EPIPE behavior under Solaris 2.4 .
So, my code now looks something like:

In article <4re7o3$6...@news.parc.xerox.com>,


Bill Fenner <fen...@parc.xerox.com> wrote:
>
> s = socket(AF_INET, SOCK_STREAM, 0);
> fcntl(s, F_SETFL, FNDELAY);
> if (connect(s, &sin, sizeof sin) < 0 && errno != EINPROGRESS)
> perror("connect");
> ... select on s for writing and do other stuff until s is ready
> ... for writing

if (getsockopt(s, SOL_SOCKET, SO_ERROR, &err, sizeof(err)) < 0) {
#ifdef SOLARIS
switch (errno) {
/*
* Solaris 2.4's socket emulation doesn't allow you
* to determine the error from a failed non-blocking
* connect and just returns EPIPE. Create a fake
* error message for connect.
*/
case EPIPE:
err = ENOTCONN;
break;

/*
* Solaris 2.5's socket emulation returns the connect
* error as a getsockopt error. If getsockopt returns
* an error that could have been returned by connect,
* use that.
*/
case ENETDOWN:
case ENETUNREACH:
case ENETRESET:
case ECONNABORTED:
case ECONNRESET:
case ENOBUFS:
case EISCONN:
case ENOTCONN:
case ESHUTDOWN:
case ETOOMANYREFS:
case ETIMEDOUT:
case ECONNREFUSED:
case EHOSTDOWN:
case EHOSTUNREACH:
case EWOULDBLOCK:
case EALREADY:
case EINPROGRESS:
err = errno;
break;

/*
* Otherwise, it's probably a real error.
*/
default:
perror("getsockopt");
return;
}
#else
perror("getsockopt");
return;
#endif


}
> if (err != 0) {
> errno = err;
> perror("connect");
> } else {
> /* Connection succeeded */
> }

It's possibly safe to eliminate the case, and just pretend that connect
returned the error if getsockopt() returns any error; I just wanted to
reduce the possibility of weird problems being incorrectly reported.

Bill

0 new messages