#include #include #include #include #include #include #include #include #include /* Return file descriptor or -1. */ int make_connection (int server, int *pservice); int main(void) { int sfd, cfd, xerrno, service; socklen_t xlen = sizeof (xerrno); sfd = make_connection (1, &service); if (sfd == -1) { fprintf (stderr, "Can't start server.\n"); exit(1); } printf ("Server listening on port %d.\n", service); cfd = make_connection (0, &service); if (cfd == -1) { fprintf (stderr, "Can't start client.\n"); exit (1); } fprintf (stderr, "Attempting client connection..."); /* Here we should use 'select' to wait for cfd to be ready for writing. To simplify the test, I’m just calling 'sleep'. */ sleep (2); if (getsockopt (cfd, SOL_SOCKET, SO_ERROR, &xerrno, &xlen)) { perror ("getsockopt"); exit (1); } if (xerrno) printf ("failure: %s.\n", strerror (xerrno)); else printf ("success.\n"); exit (0); } int make_connection (int server, int *pservice) { struct addrinfo hints, *result, *rp; int family, optval, ret, s = -1; const char *host; const char *portstring; char portbuf[128]; struct sockaddr_in sa; socklen_t len = sizeof (sa); if (server) /* Assigned port will be returned in pservice. */ { family = AF_INET; portstring = "0"; host = "127.0.0.1"; } else /* Client; desired port should be specified in pservice. */ { family = AF_UNSPEC; portstring = portbuf; sprintf (portbuf, "%d", *pservice); host = "localhost"; } memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_socktype = SOCK_STREAM; hints.ai_family = family; if (getaddrinfo (host, portstring, &hints, &result)) return -1; optval = 1; for (rp = result; rp; rp = rp->ai_next) { s = socket (rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (s == -1) continue; if (server) { if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) { perror ("setsockopt"); close (s); return -1; } if (bind (s, rp->ai_addr, rp->ai_addrlen)) { perror ("bind"); close (s); return -1; } if (listen (s, 5)) { perror ("listen"); close (s); return -1; } if (getsockname (s, (struct sockaddr *) &sa, &len)) { perror ("getsockname"); close (s); return -1; } *pservice = ntohs (sa.sin_port); } else /* Nonblocking client. */ { if (fcntl (s, F_SETFL, O_NONBLOCK) == -1) { close (s); s = -1; continue; } } ret = connect (s, rp->ai_addr, rp->ai_addrlen); if (ret == 0 || errno == EISCONN) break; if (!server && errno == EINPROGRESS) break; close (s); s = -1; } freeaddrinfo(result); return s; }